题目描述 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 }
View Code