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 }
View Code

 


posted @ 2014-03-13 08:27  Randolph87  阅读(284)  评论(0编辑  收藏  举报