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

 


你可能感兴趣的:(IO)