正题
这题看似很难,让人很容易就想到有上下界的费用流。
但是根本不用那么麻烦。
其实我们可以这样看。
对于每一条边,经过的次数大于等于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);
}