2817 Tangent的愤怒 - Wikioi
题目描述 Description 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段。 第二段:本题改编自Usaco Training 4.4.2... 第三段:本题加大了数据强度... 第四段:本题来自CH Round #1... 第五段:快去看第六段! Tangent来到OI村,想起Bread经常在他面前晒妹(Lemon),于是要把二人分隔两地,永世不能相见。 黑化的Tangent拥有了分裂大地的力量,他要分裂两人的家之间的一些路,使得Bread不能去找Lemon。(保证Bread家和Lemon家连通) 从Bread家到Lemon家的路现在可以看成是一个有向图,具有N个点,M条边。(点的编号为1~N,边的编号按照离Tangent的距离由近到远依次为1~M) Tangent想要毁坏一条边的代价是Wi。 由于Tangent想要节省力量去毁坏更多和谐的事物,所以他的炸路方案必定是总代价最小、边数量最小的,而且他希望能尽快做完这件事,所以他炸的路对应编号必定是字典序最小的。 输入描述 Input Description 第一行四个正整数N,M,S0,T0,分别表示点数,边数,Bread家的点编号,Lemon家的点编号。 接下来N行,按照边的编号依次描述每条边,每行三个正整数Si,Ti,Wi,分别表示第i条边的起点、终点和毁坏代价。 输出描述 Output Description 第一行两个正整数W和K,表示总最小代价和最小炸路数量。 接下来K行,输出最小字典序方案,每行一个正整数Number,表示第Number条边要炸毁。 样例输入 Sample Input 4 5 1 4 1 3 100 3 2 50 2 4 60 1 2 40 2 3 80 样例输出 Sample Output 60 1 3 数据范围及提示 Data Size & Hint 对于30%的数据:N\leq 10, M\leq 500 对于60%的数据:N\leq 20, M\leq 1000 对于100%的数据:N\leq 50,M\leq 5000,W_{i}\leq 10^{5}
很巧妙的做法,把边权*(m+1)+1,这样最大流/(m+1)就是原来的最大流,因为+1那一部分最多加m
最大流%(m+1)就是边数,可以保证最小割又可以保证最少边数
做一遍最大流,从小到大枚举边,判断是否在最小割里,在就删除输出,再把原来的最大流减去这条边,继续做
1 #include<cstdio> 2 using namespace std; 3 4 const int maxn=55; 5 const int maxm=5000+10; 6 7 long long map[maxn][maxn],a[maxn][maxn],w[maxm]; 8 int n,m,s,t,u[maxm],v[maxm]; 9 long long ans; 10 11 void work() 12 { 13 int i,j; 14 for(i=1;i<=n;++i) 15 for(j=1;j<=n;++j) 16 a[i][j]=map[i][j]; 17 } 18 19 long long f,aug,his[maxn]; 20 int pre[maxn],vh[maxn],dis[maxn]; 21 22 long long flow() 23 { 24 int i,j,temp,min; 25 bool flag=false; 26 f=0; 27 aug=2147000000; 28 vh[0]=n; 29 for(i=1;i<=n;++i) 30 vh[i]=0; 31 for(i=1;i<=n;++i) 32 dis[i]=0; 33 i=s; 34 while(dis[i]<n) 35 { 36 his[i]=aug; 37 flag=false; 38 for(j=1;j<=n;++j) 39 if(a[i][j]>0&dis[i]==dis[j]+1) 40 { 41 flag=true; 42 if(aug>a[i][j])aug=a[i][j]; 43 pre[j]=i; 44 i=j; 45 if(i==t) 46 { 47 f+=aug; 48 while(i!=s) 49 { 50 temp=pre[i]; 51 a[temp][i]-=aug; 52 a[i][temp]+=aug; 53 i=temp; 54 } 55 aug=2147000000; 56 } 57 break; 58 } 59 if(flag)continue; 60 min=n-1; 61 for(j=1;j<=n;++j) 62 if(a[i][j]>0&dis[j]<min)min=dis[j]; 63 --vh[dis[i]]; 64 if(vh[dis[i]]==0)break; 65 dis[i]=min+1; 66 ++vh[dis[i]]; 67 if(i!=s) 68 { 69 i=pre[i]; 70 aug=his[i]; 71 } 72 } 73 return f; 74 } 75 76 int main() 77 { 78 int i,j; 79 scanf("%d%d%d%d",&n,&m,&s,&t); 80 for(i=1;i<=m;++i) 81 { 82 scanf("%d%d%lld",&u[i],&v[i],&w[i]); 83 w[i]=w[i]*(m+1)+1; 84 map[u[i]][v[i]]+=w[i]; 85 } 86 work(); 87 ans=flow(); 88 printf("%lld %lld\n",ans/(m+1),ans%(m+1)); 89 for(i=1;i<=m;++i) 90 { 91 work(); 92 a[u[i]][v[i]]-=w[i]; 93 if(flow()+w[i]==ans) 94 { 95 printf("%d\n",i); 96 map[u[i]][v[i]]-=w[i]; 97 ans-=w[i]; 98 } 99 } 100 return 0; 101 }