hdu 3204(最小割--关键割边)

Ikki‘s Story I - Road Reconstruction

Time Limit: 2000MS   Memory Limit: 131072K
Total Submissions: 7491   Accepted: 2172

Description

Ikki is the king of a small country – Phoenix, Phoenix is so small that there is only one city that is responsible for the production of daily goods, and uses the road network to transport the goods to the capital. Ikki finds that the biggest problem in the country is that transportation speed is too slow.

Since Ikki was an ACM/ICPC contestant before, he realized that this, indeed, is a maximum flow problem. He coded a maximum flow program and found the answer. Not satisfied with the current status of the transportation speed, he wants to increase the transportation ability of the nation. The method is relatively simple, Ikki will reconstruct some roads in this transportation network, to make those roads afford higher capacity in transportation. But unfortunately, the country of Phoenix is not so rich in GDP that there is only enough money to rebuild one road. Ikki wants to find such roads that if reconstructed, the total capacity of transportation will increase.

He thought this problem for a loooong time but cannot get it. So he gave this problem to frkstyc, who put it in this POJ Monthly contest for you to solve. Can you solve it for Ikki?

Input

The input contains exactly one test case.

The first line of the test case contains two integers N, M (N ≤ 500, M ≤ 5,000) which represents the number of cities and roads in the country, Phoenix, respectively.

M lines follow, each line contains three integers a, b, c, which means that there is a road from city a to city b with a transportation capacity of c (0 ≤ a, b < n, c ≤ 100). All the roads are directed.

Cities are numbered from 0 to n − 1, the city which can product goods is numbered 0, and the capital is numbered n − 1.

Output

You should output one line consisting of only one integer K, denoting that there are K roads, reconstructing each of which will increase the network transportation capacity.

Sample Input

2 1
0 1 1

Sample Output

1

题意:从源点0到汇点n-1,问给那些边增加容量会增大整个网络的容量??输出边的数量。这里有个重要的概念:关键边,关键边定义为 :通过增加某个边的容量使得网络的最大流增加个人的理解为最小割里面的边一定是关键割边,但关键割边不一定是最小割。这题的做法是先求一次最大流,然后对残余网络进行两次DFS,从源点的DFS很简单,从正向边搜到边的容量为0即可,得到点集A,标记;主要是从汇点进行第二次DFS,这里就要用到技巧了,网络流有个神奇的反向边,我们从反向边进行DFS(也要判断一下正向边是否为0)得到点集B,标记;然后遍历所有的边,如果某条边的两个端点分别属于点集 A,B,那么这条边肯定就是关键割边,记录之。
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <string.h>
#include <math.h>
#include <iostream>
#include <math.h>
using namespace std;
const int N = 505;
const int INF = 999999999;
struct Edge
{
    int v,next;
    int w;
} edge[N*N];
int head[N];
int level[N];
int tot;
void init()
{
    memset(head,-1,sizeof(head));
    tot=0;
}
void addEdge(int u,int v,int w,int &k)
{
    edge[k].v = v,edge[k].w=w,edge[k].next=head[u],head[u]=k++;
    edge[k].v = u,edge[k].w=0,edge[k].next=head[v],head[v]=k++;
}
int BFS(int src,int des)
{
    queue<int >q;
    memset(level,0,sizeof(level));
    level[src]=1;
    q.push(src);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        if(u==des) return 1;
        for(int k = head[u]; k!=-1; k=edge[k].next)
        {
            int v = edge[k].v;
            int w = edge[k].w;
            if(level[v]==0&&w!=0)
            {
                level[v]=level[u]+1;
                q.push(v);
            }
        }
    }
    return -1;
}
int dfs(int u,int des,int increaseRoad)
{
    if(u==des) return increaseRoad;
    int ret=0;
    for(int k=head[u]; k!=-1; k=edge[k].next)
    {
        int v = edge[k].v;
        int w = edge[k].w;
        if(level[v]==level[u]+1&&w!=0)
        {
            int MIN = min(increaseRoad-ret,w);
            w = dfs(v,des,MIN);
            if(w>0)
            {
                edge[k].w -=w;
                edge[k^1].w+=w;
                ret+=w;
                if(ret==increaseRoad) return ret;
            }
            else level[v] = -1;
        }
    }
    return ret;
}
int Dinic(int src,int des)
{
    int ans = 0;
    while(BFS(src,des)!=-1) ans+=dfs(src,des,INF);
    return ans;
}
int vis[N];
void dfs0(int u)
{
    vis[u] = 1;
    for(int k=head[u]; k!=-1; k=edge[k].next)
    {
        int v = edge[k].v,w = edge[k].w;

        if(!vis[v]&&w>0)
        {
            dfs0(v);
        }
    }
}
void dfs1(int u)
{
    vis[u] = 2;
    for(int k=head[u]; k!=-1; k=edge[k].next)
    {
        int v = edge[k].v;
        if(!vis[v]&&edge[k^1].w>0&&edge[k].w>0) ///汇点利用反向边进行搜索,这里还要判断一下正向边是否大于0
        {
            dfs1(v);
        }
    }
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    init();
    for(int i=0; i<m; i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        if(u==v) continue;
        addEdge(u,v,w,tot);
    }
    memset(vis,0,sizeof(vis));
    Dinic(0,n-1);
    dfs0(0);
    dfs1(n-1);
    int ans = 0;
    for(int u=0; u<n; u++)
    {
        for(int k=head[u]; k!=-1; k=edge[k].next)
        {
            if(k%2==1) continue; ///只考虑正向边
            if(vis[u]==1&&vis[edge[k].v]==2) ans++;
        }
    }
    printf("%d\n",ans);
}
时间: 2024-08-08 22:09:50

hdu 3204(最小割--关键割边)的相关文章

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割

题意:方格取数,如果取了相邻的数,那么要付出一定代价.(代价为2*(X&Y))(开始用费用流,敲升级版3820,跪...) 建图:  对于相邻问题,经典方法:奇偶建立二分图.对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权. ans=总点权-最小割:如果割边是源->X,表示x不要选(是割边,必然价值在路径上最小),若割边是Y-汇点,同理:若割边是X->Y,则表示选Y点且选X点, 割为w( 2*(X&Y) ). 自己的确还没有理解其本质

ZOJ 3792 Romantic Value 最小割+求割边的数量

点击打开链接 Romantic Value Time Limit: 2 Seconds      Memory Limit: 65536 KB Farmer John is a diligent man. He spent a lot of time building roads between his farms. From his point of view, every road is romantic because the scenery along it is very harmon

hdu 5076 最小割灵活的运用

题意比较复杂,其实关键是抽象出来:每个点,可以赋予俩个值(二选一,必需选一个,设ai,bi).  求所有之和最大,有条件:若俩个点同时满足: 1,:点的二进制只有一位不同.  2:至少有一个是选B值: 则可获得对应加成. 这题开始想了半天,建图遇到问题,看了官方说是最小割,于是入手: a值就是小于阈值的最大值,B值就是大于等于的最大值. 思路:俩个点选其一,必然想到建二分(每个点一分为二)图,中间连无穷的边.因为只有一位不同,必然分奇偶点,有奇数个1的点,源点到他为A值,对应点到汇点为B值,偶点

There is a war (hdu 2435 最小割+枚举)

There is a war Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 970    Accepted Submission(s): 277 Problem Description There is a sea. There are N islands in the sea. There are some directional

Being a Hero (hdu 3251 最小割 好题)

Being a Hero Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1211    Accepted Submission(s): 381 Special Judge Problem Description You are the hero who saved your country. As promised, the ki

hdu 1565 最小割

黑白染色,源指向白,黑指向汇,容量都是方格中数的大小,相邻的格子白指向黑,容量为oo,然后求一次最小割. 这个割是一个简单割,如果只选择不在割中的点,那么一种割就和一个选数方案一一对应,割的大小就是不选的那些数的大小,我们需要最小化这个值. 答案=总和-最小割 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <vector> 5 #define maxn 410 6

HDU 3526 最小割

点击打开链接 题意:有两个公司分别提供的n个部件,每个部件的价格给出,现在要这买n个部件,我可以选择两个公司中的任意一个,但是对于下面给的m个关系来说,若满足i与j不再同一个公司,那么就要加上c的费用,问买n个部件的最小花费 思路:刚刚读完题的时候感觉像是最小费用流呐,流量就是5呗,然后根据关系建图,画了一会也画不出来,看了一下正解竟然是最小割,思想到时很简单,但是思路不对的话还是很难想到的,建图就是源点,中间一列n个部件,然后汇点,源点连中间的话就是A公司的n个物品,然后中间连汇点的话就是B公

[BZOJ 1797][AHOI2009]最小割(最小割关键边的判断)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1797 分析: 在残余网络中看: 对于第1问: 1.首先这个边必须是满流 2.其次这个边连接的两个点U,V必须属于两个SCC,即这个边必须为一个割 对于第2问: 在第1问的基础上,还要判断U和S.V和T是否分别在同一个SCC中,如果成立,那么这样才是必须的.

hdu 1569 最小割

和HDU 1565是一道题,只是数据加强了,貌似轮廓线DP来不了了. 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <vector> 5 #define maxn 2510 6 #define oo 0x3f3f3f3f 7 using namespace std; 8 9 struct Edge { 10 int u, v, f; 11 Edge( int u,