【BZOJ3265】志願者招募加強版 線性規劃 單純形法 對偶原理
連結:
#include <stdio.h>
int main()
{
puts("轉載請註明出處[vmurder]謝謝");
puts("網址:blog.csdn.net/vmurder/article/details/45673079");
}
題解:
這道題是線性規劃求目標函式最小值 ,對偶原理轉一下就成了單純形演算法求線性規劃最大值。
單純形法:
首先這篇部落格缺失了很多證明,只能講述單純形法的實現。
// N個變數 M個限制
double a[M][N]; // 這m個限制裡變數的係數
double b[M]; // 第i個限制加和 <=bi
double c[N]; // 目標函式裡變數係數
double ans; // 目標函式自帶的係數
void pivot(int x,int y); // 轉軸操作
void solve();
首先對於如下資料
3 3
2 3 4
1 1 2 2
1 2 3 5
1 3 3 2
我們可以得到以下的限制:
目標函式:
2x_1+5x_2+2x_3+0
限制函式:
x_1\leq2
x_1+x_2\leq3
x_2+x_3\leq4
然後若
x_4 x_5 x_6
均為任意值。 那麼我們可以將式子表示為
狀態 1: **************
目標函式:
2x_1+5x_2+2x_3+0
限制函式:
x_4+1x_1=2
x_5+1x_1+1x_2=3
x_6+1x_2+1x_3=4
然後在單純形的過程中函式們的各系數得到改變的過程如下:
狀態 1: **************
目標函式:
2x_1+5x_2+2x_3+0
限制函式:
x_4+1x_1=2
x_5+1x_1+1x_2=3
x_6+1x_2+1x_3=4
狀態 2: **************
目標函式:
-2x_4+5x_2+2x_3+4
限制函式:
x_1+1x_4=2
x_5+-1x_4+1x_2=1
x_6+1x_2+1x_3=4
狀態 3: **************
目標函式:
3x_4+-5x_5+2x_3+9
限制函式:
x_1+1x_4=2
x_2+-1x_4+1x_5=1
x_6+1x_4+-1x_5+1x_3=3
狀態 4: **************
目標函式:
-3x_1+-5x_5+2x_3+15
限制函式:
x_4+1x_1=2
x_2+1x_1+1x_5=3
x_6+-1x_1+-1x_5+1x_3=1
狀態 5: **************
目標函式:
-1x_1+-3x_5+-2x_6+17
限制函式:
x_4+1x_1=2
x_2+1x_1+1x_5=3
x_3+-1x_1+-1x_5+1x_6=1
線性規劃最終答案:17
單純形思想:
其實就是每次找一個在目標函式中存在的變數,跟不在其中的某個變數交換一下,然後換來換去最終目標函式中所有變數係數都為負了,那麼目標函式最後加的常數就是答案辣。
單純形實現:
具體的實現過程呢?
struct Simplex
{
int n,m; // n個變數、m個限制
double a[M][N],b[M],c[M],ans;
void pivot(int x,int y)
{
int i,j;
double t;
b[x]/=a[x][y];
for(i=1;i<=n;i++)if(i!=y)a[x][i]/=a[x][y];
a[x][y]=1.0/a[x][y];
for(i=1;i<=m;i++)if(i!=x&&fabs(a[i][y])>eps)
{
b[i]-=a[i][y]*b[x],t=a[i][y];
for(j=1;j<=n;j++)a[i][j]-=t*a[x][j];
a[i][y]=-t*a[x][y];
}
ans+=c[y]*b[x],t=c[y];
for(i=1;i<=n;i++)c[i]-=t*a[x][i];
c[y]=-t*a[x][y];
}
double solve()
{
read();
double t;
for(int i,x,y;;)
{
for(i=1;i<=m;i++)if(c[i]>eps){y=i;break;}
if(i>m)return ans;
for(t=inf,i=1;i<=m;i++)
if(a[i][y]>eps&&t>b[i]/a[i][y])
x=i,t=b[i]/a[i][y];
if(t==inf)return t;
else pivot(x,y);
}
}
}simplex;
下面的實現裡存在兩個坑,請不要深究它們怎麼證。
double~solve()
:
首先我們每次找一個標號最靠前的【坑1】目標函式中係數為正的變數
y
(如第30行),然後如果找不到,就表示已經找到了最優解【坑2】。
然後我們找這個變數在哪個限制裡是”最緊”的【坑3】,即33、34、35這三行。
如果找不到任何一個”緊”的行,即
\forall a(i,y)<=eps
那麼這個變數想多大就能多大,反正有輔助變數頂著,可以直接返回無界【坑4】,即答案是無窮大。
然後我們對此限制中的輔助變數和找到的
y
進行轉軸操作。
void~pivot(int~x,int~y)
:
先把第
x
個限制的係數改一改,然後用它去消其它的限制,再消一下目標函式。結束。類似高斯消元?
對偶原理:
如果要求最小值,那麼我們把模型對偶一下就可以辣。【坑5】
即限制矩陣 【轉置】 一下,然後目標函式的係數和每個限制的最終
\leq
的那個值也互換一下。
【轉置】 :矩陣的元素
a(i,j)
變為 a(j,i)
。
對於證明坑的總結:
【坑1】為什麼要找標號最小的?
根據Bland法則,這麼做可以避免被卡死迴圈。
【坑2】為什麼標號都是負的就表示找到了最優解?
表示無法理解為什麼不能給某個存在負係數的變數轉一轉。
【坑3】為什麼要找”最緊”的?
不知道不知道。
【坑4】為什麼直接返回無界了?
不可以別的某個變數再來轉一轉,然後就迴歸有界?
【坑5】對偶原理是毛線?
天然坑,深坑。
程式碼:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1010 // 變數個數
#define M 10100 // 限制個數
#define inf 1e9
#define eps 1e-5
using namespace std;
struct Simplex
{
int n,m; // n個變數、m個限制
double a[M][N],b[M],c[M],ans;
void read()
{
int i,j,k,l,r;
scanf("%d%d",&m,&n);
for(i=1;i<=m;i++)scanf("%lf",&c[i]);
for(i=1;i<=n;i++)
{
scanf("%d",&k);
while(k--)
{
scanf("%d%d",&l,&r);
for(j=l;j<=r;j++)a[i][j]=1.0;
}
scanf("%lf",&b[i]);
}
swap(n,m);
}
void pivot(int x,int y)
{
int i,j;
double t;
b[x]/=a[x][y];
for(i=1;i<=n;i++)if(i!=y)a[x][i]/=a[x][y];
a[x][y]=1.0/a[x][y];
for(i=1;i<=m;i++)if(i!=x&&fabs(a[i][y])>eps)
{
b[i]-=a[i][y]*b[x],t=a[i][y];
for(j=1;j<=n;j++)a[i][j]-=t*a[x][j];
a[i][y]=-t*a[x][y];
}
ans+=c[y]*b[x],t=c[y];
for(i=1;i<=n;i++)c[i]-=t*a[x][i];
c[y]=-t*a[x][y];
}
double solve()
{
read();
double t;
for(int i,x,y;;)
{
for(i=1;i<=m;i++)if(c[i]>eps){y=i;break;}
if(i>m)return ans;
for(t=inf,i=1;i<=m;i++)
if(a[i][y]>eps&&t>b[i]/a[i][y])
x=i,t=b[i]/a[i][y];
if(t==inf)return t;
else pivot(x,y);
}
}
}simplex;
int main()
{
// freopen("test.in","r",stdin);
printf("%d\n",(int)(simplex.solve()+eps));
return 0;
}
相關文章
- 線性規劃對偶原理
- 線性規劃單純形法精解
- 解析對偶理論與對偶單純性法
- 掘金翻譯計劃招募志願者啦
- 對偶單純形法演算法精要演算法
- 對偶理論和對偶單純形法——Python實現Python
- 線性規劃對偶學習筆記筆記
- Android 谷歌官方文件抓蟲計劃志願者招募中Android谷歌
- 【活動】Apache Flink文件翻譯志願者招募!Apache
- 線性規劃的對偶問題——由拉格朗日對偶問題匯出
- 線性規劃之單純形演算法矩陣描述與python實現演算法矩陣Python
- 社群活動| Apache Pulsar 中文開發者與使用者組志願者招募Apache
- 成都大運會“全球網路安全志願者聯盟”招募令
- 運籌優化(四)--線性規劃之對偶問題和靈敏度分析優化
- 志願者招募 | 2018 掘金開發者大會 · 微信小程式專場微信小程式
- 三國志11遊戲威力加強版遊戲
- 簡單題 加強版
- 關於 線性規劃 非線性規劃 與 凸優化優化
- matlab線性規劃Matlab
- 動態規劃-----線性動態規劃
- 志願者招募令|來!一起Build OceanBase第一次開發者大會UI
- 運籌優化(五)--線性規劃之內點法優化
- 三國志11威力加強版 for Mac遊戲下載Mac遊戲
- 運籌學——matlab實現單純形法Matlab
- 烏克蘭招募黑客志願軍攻擊俄羅斯關鍵機構黑客
- 動態規劃篇——線性DP動態規劃
- matlab求解非線性規劃Matlab
- UVA 10498 Happiness!(線性規劃)APP
- 線性規劃模型複習總結模型
- matlab求解線性規劃問題Matlab
- 三國志11威力加強版 for Mac(三國策略遊戲)Mac遊戲
- 三國志11威力加強版Mac(三國策略遊戲)Mac遊戲
- 蘋果計劃加強雲端計算業務對抗谷歌亞馬遜蘋果谷歌亞馬遜
- Matlab解決線性規劃問題Matlab
- Python求解線性規劃——PuLP使用教程PythonPulp
- ERP的核心——線性規劃模型(轉)模型
- 火神山醫院今日開始接收患者;比特幣價格飆升;Mozilla裁員之後招募志願者填補空缺比特幣
- 走向世界!第1屆全球學生開源年會 sosconf 2019 招募志願者開始報名!