1. 程式人生 > >【最小割輸出路徑】 UVA

【最小割輸出路徑】 UVA

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, nin 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條邊,給你每條邊割掉的權值
問讓1,2兩點走不通且用最小花費,應該怎麼割
輸出割的邊
其實就是最小割的問題
以前一直不明白Dinic內部的level陣列,做題都是套板子,這次就不行了
感謝男朋友讓我知道level陣列是用來儲存路徑上從st開始能走到的所有點
所以被割的邊,一邊沒有被level標記,一邊被標記了
輪一下每條邊,找到符合的邊輸出就行


#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAX_V=2005;
const int st=0;
const int en=2000;
const int INF=0x3f3f3f3f;
int cx[505],cy[505];
struct edge
{
    int to,cap,rev; //用於表示邊的結構體(終點,容量,反向邊)
};

vector <edge> G[MAX_V]; //圖的鄰接表表示
int level[MAX_V];   //頂點到源點的距離標號
int iter[MAX_V];    //當前弧,在其之前的邊已經沒有用了
char a[222];

void add_edge(int from,int to,int cap)
{
    G[from].push_back((edge){to,cap,G[to].size()});
    G[to].push_back((edge){from,cap,G[from].size()-1});
}

void bfs(int s)  //通過bfs計算從源點出發的距離標號
{
    memset(level,-1,sizeof(level));
    queue <int> q;
    level[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int v=q.front();q.pop();
        for(int i=0;i<G[v].size();i++)
        {
            edge &e=G[v][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to]=level[v]+1;
                q.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f)  //通過dfs尋找增廣路
{
    if(v==t) return f;
    for(int &i=iter[v];i<G[v].size();i++)
    {
        edge &e=G[v][i];
        if(e.cap>0&&level[v]<level[e.to])
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}

int max_flow(int s,int t)
{
    int flow=0;
    for(;;)
    {
        bfs(s); //計算層次圖
        if(level[t]<0) return flow; //找不到s-t路徑
        memset(iter,0,sizeof(iter)); //初始化當前弧
        int f;
        while((f=dfs(s,t,INF))>0)  //更新最大流
            flow+=f;
    }
    return flow;
}

int main()
{
    int n,m,s,d;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0) break;
        for(int i=0;i<=MAX_V;i++) G[i].clear();
        for(int i=1;i<=m;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
            cx[i]=u,cy[i]=v;
        }
        max_flow(1,2);
        for(int i=1;i<=m;i++)
        {
            if((level[cx[i]]!=-1&&level[cy[i]]==-1)||(level[cx[i]]==-1&&level[cy[i]]!=-1))
            {
                printf("%d %d\n",cx[i],cy[i]);
            }
        }
        printf("\n");
    }
    return 0;
}