[AHOI2014/JSOI2014]支線劇情,洛谷P4043,線性規劃
阿新 • • 發佈:2018-12-04
正題
這題看似很難,讓人很容易就想到有上下界的費用流。
但是根本不用那麼麻煩。
其實我們可以這樣看。
對於每一條邊,經過的次數大於等於1.
而對於每一個點,入度的經過次數總和大於等於出度的經過次數總和。
我們就可以寫成m+n條約束。
然後我們要使得每條邊經過次數乘單價最小。
因為約束都是大於等於,而且求最小值。那麼我們就對偶一下。
但是發現矩陣非常大。因為。
怎麼辦?
發現對於每一條邊,,可以寫成,我們用一個新變數y。使得
那麼,這條約束是不用寫進矩陣裡面的,因為對於矩陣裡面的基變數和非基變數,我們都已經規定了他們的值是大於等於0的。
接著,因為,所以,我們就把第二類約束中的xi全部換成yi。
又因為對偶,所以現在每條約束的上限其實就是單價,單價大於0,滿足基可行解的形式。
我們就可以直接求一便單純形就好了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define INF 2147483647
using namespace std;
int n;
double a[5010][310];
int len=0;
double eps=1e-8;
void pivot(int x,int y){
double temp=a[x][y];a[x][y]=1;
for(int i=0;i<=n;i++) a[x][i]/=temp;
for(int i=0;i<=len;i++) if(x!=i){
temp=a[i][y];a[i][y]=0;
for(int j=0;j<=n;j++) a[i][j]-=temp*a[x][j];
}
}
void simplex(){
double mmin;
int x,y;
while(true){
x=y=0;
for(int i=1;i<=n;i++) if(a[0][i]>eps && (y==0 || a[0][i]>a[0][y])) y=i;
if(y==0) break;
mmin=(double)1e15;
for(int i=1;i<=len;i++) if(a[i][y]>eps && a[i][0]/a[i][y]<mmin) x=i,mmin=a[i][0]/a[i][y];
if(x==0) break;
pivot(x,y);
}
}
int main(){
srand(2333);
scanf("%d",&n);
int k,b,c;
double tot=0;
for(int i=1;i<=n;i++){
scanf("%d",&k);
for(int j=1;j<=k;j++){
scanf("%d %d",&b,&c);
len++;if(i!=1) a[len][i]=-1,a[0][i]+=1;
a[len][b]=1,a[0][b]-=1;a[len][0]=c;tot+=c;
}
}
simplex();
printf("%.0lf",-a[0][0]+tot);
}