【BZOJ3112】[ZJOI2013] 防守戰線(單純形法與線性規劃)
阿新 • • 發佈:2020-07-18
大致題意: \(\begin{align}min\ \ &\sum_{j=1}^nc_jx_j&\\s.t.\ \ &\sum_{j=l_i}^{r_i}x_j\ge b_i&i=1,2,...,m\\&x_j\ge0&j=1,2,...,n\end{align}\)
對偶圖
首先,我們把它轉化一下,令\(a_{i,j}=[j\in[l_i,r_i]]\),得到:
\[\begin{align}min\ \ &\sum_{j=1}^nc_jx_j&\\s.t.\ \ &\sum_{j=1}^na_{i,j}x_j\ge b_i&i=1,2,...,m\\&x_j\ge0&j=1,2,...,n\end{align} \]
然後我們發現,這東西和我們熟知的線性規劃式子並不一樣,它求的是最小值,且限制中式子的符號都是大於等於,剛好和線性規劃相反。
然而,有一種名叫線性規劃對偶的東西,證明這個問題的最優解等同於下面這個問題的最優解:
\[\begin{align}max\ \ &\sum_{j=1}^nb_jx_j&\\s.t.\ \ &\sum_{j=1}^na_{j,i}x_j\le c_i&i=1,2,...,m\\&x_j\ge0&j=1,2,...,n\end{align} \]
而這就是經典的線性規劃,直接套板子即可。
除此之外,這裡限制矩陣的係數只有\(0,1\)
程式碼
#include<bits/stdc++.h> #define Tp template<typename Ty> #define Ts template<typename Ty,typename... Ar> #define Reg register #define RI Reg int #define Con const #define CI Con int& #define I inline #define W while #define N 1000 #define M 10000 #define DB double #define eps 1e-8 using namespace std; int n,m;DB a[N+5][M+5]; namespace SimplexMethod//限制矩陣只有0,1,簡化版的單純形法 { I void Pivot(CI l,CI e) { RI i,j;DB t=a[l][e];for(a[l][e]=1,i=0;i<=n;++i) a[l][i]/=t; for(i=0;i<=m;++i) if(i^l&&fabs(a[i][e])>eps) for(t=a[i][e],a[i][e]=j=0;j<=n;++j) a[i][j]-=t*a[l][j]; } I void Simplex() { RI i,l,e;DB Mn;W(1) { for(l=e=0,Mn=1e9,i=1;i<=n;++i) if(a[0][i]>eps) {e=i;break;}if(!e) return; for(i=1;i<=m;++i) a[i][e]>eps&&a[i][0]/a[i][e]<Mn&&(Mn=a[i][0]/a[i][e],l=i);Pivot(l,e); } } I void Solve() {Simplex(),printf("%d\n",(int)(-a[0][0]+0.5));}//四捨五入得到整數 }; int main() { RI i,j,x,y;for(scanf("%d%d",&m,&n),i=1;i<=m;++i) scanf("%lf",a[i]);//注意對偶 for(i=1;i<=n;++i) for(scanf("%d%d%lf",&x,&y,a[0]+i),j=x;j<=y;++j) a[j][i]=1; return SimplexMethod::Solve(),0;//單純形法 }