起因是一道Timus的題目 , 長着一副經典的線性規劃的模樣:
單純形法本身並不難理解 , 只是有很多名詞可能讓剛開始看的小夥伴有點爲難。這裏推薦一篇論文入門非常不錯。 看到
BZOJ 1061 志願者招募
這裏設志願者數量的向量爲
但這個線性規劃不好找基本解 , 所以我們嘗試把這玩意對偶:
由於本題我們只求目標值而不用求對應的方案所以 , 我們其實只需要把那個矩陣轉置一下就好啦。 (並不推薦寫網上的某些寫法 , 把一個好好的矩陣拆成三個QAQ)
誒 , 當你正準備用單純形法求這玩意的最大值的時候你會發現 , 這玩意好像我存不下。 因爲當我添加了若干鬆弛變量之後 , 這玩意就是
當時這裏我糾結了很久 , 但這就是一個很常見的針對稀疏矩陣的優化(弱省的學生學校裏沒有善良的學長啊)。
思路就是有的變量那一個列向量只有一個係數爲1的值(其餘都是0) , 所以我們不存這些東西 , 當我們
至此 ,此題就可以AC了。
這裏貼一個會MLE但是思路清晰的代碼 , 自己做的時候可以把
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <deque>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <cassert>
using namespace std;
const int maxn = 1100;
const int maxm = 11000;
const double eps = 1e-7;
const double INF = 1e20;
int dcmp(double a) { return fabs(a)<eps?0:a<0?-1:1; }
int n , m;
double b[maxn][maxm] , a[maxm][maxn];
void dualize()
{
swap(++n, ++m);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j] = b[j][i];
}
void pivot(int l , int e)
{
for(int i=1;i<=n;i++) if(i!=l && dcmp(a[i][e]))
{
for(int j=1;j<=m;j++) if(j!=e) a[i][j] -= a[i][e]/a[l][e]*a[l][j];
a[i][e] /= -a[l][e];
}
for(int i=1;i<=m;i++) if(i!=e) a[l][i] /= a[l][e]; a[l][e] = 1/a[l][e];
}
double simplex()
{
double mn;
int e , l;
while(true)
{
for(e=1;e<m;e++) if(dcmp(a[n][e]) > 0) break;
if(e == m) return -a[n][m];
mn = INF;
for(int i=1;i<n;i++) if(dcmp(a[i][e]) > 0 && mn > a[i][m]/a[i][e]) mn = a[l=i][m]/a[i][e];
if(mn == INF) return INF;
pivot(l, e);
}
}
int main(int argc, char *argv[]) {
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%lf" , &b[i][m+1]);
for(int i=1,l,r,v;i<=m;i++)
{
scanf("%d%d%d" , &l,&r,&v);
for(int j=l;j<=r;j++) b[j][i] = 1;
b[n+1][i] = v;
}
dualize();
printf("%d" , (int)(simplex()+0.50));
return 0;
}
一些問題:
Q: 這玩意本來沒次
A: 數據不好 , 好的話一樣超時……
Q: 爲什麼你不記錄此時的到底是哪些是鬆弛變量啊, 這樣到最後不就不知道哪些變量的對應關係了麼?
A: 是的 , 我確實應該記錄這些變量的對應關係 , 但是此題不要求輸出方案 , 這就免了(博主懶)
Q: 我看到網上的很多單純形的代碼很長的樣子 , 你的代碼這麼短有沒有暗傷啊?
A: 博主巨弱 , 表示目前沒有發現
一個小小的總結:
我後來又嘗試用單純形法解決網絡流的題目 , 正確性和通解的優勢是明顯的 , 因爲通過代數建模比通過圖論構造要靈活很多 , 就想用解析幾何來做幾何題一樣。但是很多題目, 無論是時間還是空間都很緊迫 , 所以此方法在大多時候都不能上“正席” , 但是如果考試的時候一個網絡流題目建模困難 , 而你會單純形法 , 那麼……(自由想象)