UVA10480 Sabotage (最小割+求路径)

The regime of a small but wealthy dictatorship has been abruptly overthrown by an unexpected rebellion.
Because of the enormous disturbances this is causing in world economy, an imperialist military
super power has decided to invade the country and reinstall the old regime.
For this operation to be successful, communication between the capital and the largest city must
be completely cut. This is a difficult task, since all cities in the country are connected by a computer
network using the Internet Protocol, which allows messages to take any path through the network.
Because of this, the network must be completely split in two parts, with the capital in one part and
the largest city in the other, and with no connections between the parts.
There are large differences in the costs of sabotaging different connections, since some are much
more easy to get to than others.
Write a program that, given a network specification and the costs of sabotaging each connection,
determines which connections to cut in order to separate the capital and the largest city to the lowest
possible cost.
Input
Input file contains several sets of input. The description of each set is given below.
The first line of each set has two integers, separated by a space: First one the number of cities, n in
the network, which is at most 50. The second one is the total number of connections, m, at most 500.
The following m lines specify the connections. Each line has three parts separated by spaces: The
first two are the cities tied together by that connection (numbers in the range 1 − n). Then follows the
cost of cutting the connection (an integer in the range 1 to 40000000). Each pair of cites can appear
at most once in this list.
Input is terminated by a case where values of n and m are zero. This case should not be processed.
For every input set the capital is city number 1, and the largest city is number 2.

Output
For each set of input you should produce several lines of output. The description of output for each set
of input is given below:
The output for each set should be the pairs of cities (i.e. numbers) between which the connection
should be cut (in any order), each pair on one line with the numbers separated by a space. If there is
more than one solution, any one of them will do.
Print a blank line after the output for each set of input.

>

Sample Input
5 8
1 4 30
1 3 70
5 3 20
4 3 5
4 5 15
5 2 10
3 2 25
2 4 50
5 8
1 4 30
1 3 70
5 3 20
4 3 5
4 5 15
5 2 10
3 2 25
2 4 50
0 0

>

Sample Output
4 1
3 4
3 5
3 2
4 1
3 4
3 5
3 2

题意:给出n个点,m条边,以及切断每条边的权值,求最小割并输出割的哪几条边

求最小割很简单,直接上最大流模板就行了,关键是如何输出割的哪几条边
流程:
当跑完最大流算法后,以源点为起点,dfs遍历所有可以到达的点,这些点都在S集合里,此时未被遍历到的点在T集合里
然后只需要遍历所有的边,如果这条边的一端在S集合里,另一端在T集合里,那么他就是需要割的边

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=1000+50;
const int maxm=1e6+50;
struct node
{
    node(){};
    node(int tv,int tw,int tnext){v=tv,w=tw,next=tnext;};
    int v,w,next;
}e[maxm];
int first[maxn],vis[maxn],dis[maxn],tot;
void add_edge(int u,int v,int w)
{
    e[tot]=node(v,w,first[u]);
    first[u]=tot++;
    e[tot]=node(u,w,first[v]);
    first[v]=tot++;
}
int bfs(int s,int t)
{
    mem(vis,0);
    mem(dis,0);
    queue<int>q;
    q.push(s);
    vis[s]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=first[u];~i;i=e[i].next)
        {
            if(!vis[e[i].v]&&e[i].w>0)
            {
                vis[e[i].v]=1;
                dis[e[i].v]=dis[u]+1;
                q.push(e[i].v);
            }
        }
    }
    return dis[t];
}
int dfs(int u,int t,int flow)
{
    if(u==t)return flow;
    for(int i=first[u];~i;i=e[i].next)
    {
        if(dis[e[i].v]==dis[u]+1&&e[i].w>0)
        {
            int dd=dfs(e[i].v,t,min(e[i].w,flow));
            if(dd)
            {
                e[i].w-=dd;
                e[i^1].w+=dd;
                return dd;
            }
        }
    }
    dis[u]=0;
    return 0;
}
int Dinic(int s,int t)
{
    int ans=0,flow;
    while(bfs(s,t))
    {
        while(flow=dfs(s,t,INF))
            ans+=flow;
    }
    return ans;
}
void init()
{
    mem(first,-1);
    tot=0;
}
bool check[maxn][maxn];
int main()
{
    int n,m,x,y,z;
    while(~scanf("%d%d",&n,&m)&&n+m)
    {
        init();
     for(int i=0;i<m;i++)
     {
         scanf("%d%d%d",&x,&y,&z);
        add_edge(x,y,z);
     }
      Dinic(1,2);
      bfs(1,2);
      mem(check,0);
     for(int i=0;i<tot;i++)
     {
         int u=e[i^1].v;
         int v=e[i].v;
         if(((!vis[u]&&vis[v])||(!vis[v]&&vis[u]))&&!check[u][v])
            {
                check[u][v]=check[v][u]=1;
                printf("%d %d\n",u,v);
            }
     }
     printf("\n");
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值