ZOJ 2532 Internship && POJ 3204 Ikki's Story I - Road Reconstruction【网络流的性质,最小割中的关键边】

ZOJ 2532 Internship && POJ 3204 Ikki's Story I - Road Reconstruction【网络流的性质,最小割中的关键边】

ZOJ Problem Set - 2532
Internship Time Limit: 5 Seconds      Memory Limit: 32768 KB

CIA headquarter collects data from across the country through its classified network. They have been using optical fibres long before it's been deployed on any civilian projects. However they are still under a lot pressure recently because the data are growing rapidly. As a result they are considering upgrading the network with new technologies that provide a few times wider bandwidth. In the experiemental stage, they would like to upgrade one segment of their original network in order to see how it performs. And as a CIA intern it's your responsibility to investigate which segment could actually help increase the total bandwidth the headquarter receives, suppose that all the cities have infinite data to send and the routing algorithm is optimized. As they have prepared the data for you in a few minutes, you are told that they need the result immediately. Well, practically immediately.

Input

Input contains multiple test cases. First line of each test case contains three integers n, m and l, they represent the number of cities, the number of relay stations and the number of segments. Cities will be referred to as integers from 1 to n, while relay stations use integers from n+1 to n+m. You can saves assume that n + m <= 100, l <= 1000 (all of them are positive). The headquarter is identified by the integer 0.

The next l lines hold a segment on each line in the form of a b c, where a is the source node and b is the target node, while c is its bandwidth. They are all integers where a and b are valid identifiers (from 0 to n+m). c is positive. For some reason the data links are all directional.

The input is terminated by a test case with n = 0. You can safely assume that your calculation can be housed within 32-bit integers.

Output

For each test print the segment id's that meets the criteria. The result is printed in a single line and sorted in ascending order, with a single space as the separator. If none of the segment meets the criteria, just print an empty line. The segment id is 1 based not 0 based.

Sample Input
2 1 3
1 3 2
3 0 1
2 0 1
2 1 3
1 3 1
2 3 1
3 0 2
0 0 0
Sample Output
2 3

&lthey here is an invisible empty line>

题目链接,请日这里:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2532


题目大意:

给你一个图,N个流入点,M个中继点,一个汇点0,流入点有无限流输入。

再给你L条有向边(这个很关键,影响建图和搜索的性质),问这L条边中哪些边的容量增大会使总流量增大。

按“边的序号增序“输出边。

无此类边输出空行。

吐个槽:这就是传说中的“牵一发而动全身“边么~?

解法:

建超级源N+M+1,和前N个点连边,容量无限。

求一遍最大流。在残量网络上找所求边,这里不好说其定义,个人yy觉得是满流边和某些初始容量为0的边。

找这种边的两种方法:

法1

标记出我yy的这种边,然后枚举这些边,增加其容量,再做最大流。下界是L次最大流。

因为数据没有卡这种方法,所以可水过。。。

法2

从源点和汇点分别出发黑白染色。在残量网络上,源可达的点染黑色,汇可达的点(即其反边容量大于0,也即残量网络上可达汇的点)染白色。

然后按序输出,出发点为黑色,到达点为白色的边的序号。(黑1白2初始化为0)



注意点:

1.最大流用SAP,挺快的。。但是L=1000次的SAP也是不可能过这道5s的题的。。。。

2.边数为 L * 2 + N * 2

3.搜的时候其实可以限制条件其实可以加上一句,源点出发的边必须为偶数边(邻接表的编号),汇点出发的必须为奇数边。即源点开始只搜正边,汇点只搜反边。
但实际上,根本没必要,因为超级源的性质,导致所有流向流入点的正边一定不会被增广,即其反边(流入点流出的边,且编号为奇数)的残留容量一定为0。
这就保证了搜索的正确性。所以哪怕加边的时候出现(流入点到流入点)的犯二组合,也不会对搜索结果产生影响。
(此要点的关键问题在于哪些边要搜,哪些边不要搜。)
4.输出边的时候要注意,一定要出发点黑色,到达点白色才是要找的关键边。
如果出发点白色,到达点黑色,只能证明,出发点可达汇点,到达点源点可达。不能证明该边是关键边。
因为流不从这条边上流,增加容量也不会导致流量增加。

/*
Coded by BUPT-[aswmtjdsj] @ Penalty in 915
*/
/*
SAP + DFS to find key edges on the remaining network
*/
#include 
< iostream >
#include 
< cstdio >
#include 
< cstring >
#include 
< sstream >
#include 
< fstream >
#include 
< cctype >
#define  maxn 120
#define  maxe 4000
using   namespace  std;
const   int  inf  =   ~ 0u >> 1 ;
struct  edge
{
    
int  p,next,val,anti;
    edge(){}
    edge(
int  a, int  b, int  c, int  d):p(a),next(b),val(c),anti(d){}
}v[maxn],e[maxe],arc[maxn],path[maxn];
int  flow[maxn],cnt[maxn],d[maxn],pre[maxn];
int  n,tot;
// n is the mark of the endpoint
// 0 to n
// added to (n + 1) 's point
void  init()
{
    tot 
=   0 ;
    
for ( int  i  =   0 ;i  <=  n;i ++ )
    {
        d[i] 
=   0 ;
        cnt[i] 
=   0 ;
        v[i].next 
=   - 1 ;
    }
    cnt[
0 =  n  +   1 ;
}
void  add( int  p, int  q, int  val)
{
    e[tot] 
=  edge(q,v[p].next,val,tot  +   1 );
    v[p].next 
=  tot ++ ;
    e[tot] 
=  edge(p,v[q].next, 0 ,tot  -   1 );
    v[q].next 
=  tot ++ ;
}
int  mflow( int  s, int  t)
{
    
int  k,least,loc,i,now,total;
    
bool  flag;
    
for ( int  i  =   0 ;i  <=  n;i ++ )
        arc[i].next 
=  v[i].next;
    
for (i  =  s,total  =   0 ,now  =  inf;d[s]  <  n  +   1 ;)
    {
        flow[i] 
=  now;
        
for (flag  =   false ,k  =  arc[i].next; ~ k;k  =  e[k].next)
        {
            
if (e[k].val  >   0   &&  d[i]  ==  d[e[k].p]   +   1 )
            {
                now 
=  min(e[k].val,now);
                pre[e[k].p] 
=  i;
                path[e[k].p].next 
=  k;
                arc[i].next 
=  k;
                i 
=  e[k].p;
                
if (i  ==  t)
                {
                    
for (total  +=  now;i  !=  s;i  =  pre[i])
                    {
                        e[path[i].next].val 
-=  now;
                        e[e[path[i].next].anti].val 
+=  now;
                    }
                    now 
=  inf;
                }
                flag 
=   true ;
                
break ;
            }
        }
        
if ( ! flag)
        {
            
for (least  =  n,k  =  v[i].next; ~ k;k  =  e[k].next)
            {
                
if (e[k].val  &&  d[e[k].p]  <  least)
                {
                    loc 
=  k;
                    least 
=  d[e[k].p];
                }
            }
            arc[i].next 
=  loc;
            cnt[d[i]]
-- ;
            
if (cnt[d[i]]  ==   0 )
                
break ;
            d[i] 
=  least  +   1 ;
            cnt[d[i]]
++ ;
            
if (i  !=  s)
            {
                i 
=  pre[i];
                now 
=  flow[i];
            }
        }
    }
    
return  total;
}
struct  line
{
    
int  a,b,c;
    line(){}
    line(
int  _a, int  _b, int  _c):a(_a),b(_b),c(_c){}
}l[
1005 ];
int  color[maxn];
void  dfs1( int  x, int  c)
{
    color[x] 
=  c;
    
for ( int  k  =  v[x].next; ~ k;k  =  e[k].next)
        
if ( ! color[e[k].p]  &&  e[k].val  >   0 )
            dfs1(e[k].p,c);
}
void  dfs2( int  x, int  c)
{
    color[x] 
=  c;
    
for ( int  k  =  v[x].next; ~ k;k  =  e[k].next)
        
if ( ! color[e[k].p]  &&  e[k  ^   1 ].val)
            dfs2(e[k].p,c);
}
int  main()
{
    
int  N,M,L;
    
while (scanf( " %d %d %d " , & N, & M, & L)  ==   3   &&  N)
    {
        n 
=  N  +  M  +   1 ;
        init();
        memset(color,
0 , sizeof (color));
        
for ( int  i  =   1 ;i  <=  N;i ++ )
            add(n,i,inf);
        
for ( int  i  =   1 ;i  <=  L;i ++ )
        {
            
int  a,b,c;
            scanf(
" %d %d %d " , & a, & b, & c);
            l[i] 
=  line(a,b,c);
            add(a,b,c);
        }
        
int  ans  =  mflow(n, 0 );
        
// cout << "ans" << ans << endl;
        
// in-order arc is all even arc
        
// re-order arc is all odd arc
        dfs1(n, 1 ); // colored
        dfs2( 0 , 2 );
        
bool  mark  =   false ;
        
for ( int  i  =   1 ;i  <=  L;i ++ )
        {
            
// if(color[l[i].a] && color[l[i].b] && color[l[i].a] != color[l[i].b])  // WA
             if (color[l[i].a]  ==   1   &&  color[l[i].b]  ==   2 // AC
            {
                
if ( ! mark)
                    mark 
=   true ;
                
else
                    putchar(
'   ' );
                printf(
" %d " ,i);
            }
        }
        puts(
"" );
    }
}

题目链接:http://poj.org/problem?id=3204
Ikki's Story I - Road Reconstruction
Time Limit: 2000MS Memory Limit: 131072K
Total Submissions: 4573 Accepted: 1217

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 NM (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 abc, which means that there is a road from city a to city b with a transportation capacity of c (0 ≤ ab < nc ≤ 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

Source

POJ Monthly--2007.03.04, Ikki

和浙大代码不同的是,不需要输入解的方案,只需要输出关键边的数量即可。。。

注意:dfs不设置限制条件的话,这题竟然没有TLE,而是先RE(爆栈)了。。。。- -|已访问过的点一定要判定一下啊。。哪怕根据割的性质,一个点不会被两种颜色染色。

#include  < iostream >
#include 
< cstdio >
#include 
< cstring >
using   namespace  std;
#define  maxn 505
#define  maxm 10100
const   int  inf  =   ~ 0u   >>   1 ;
struct  edge
{
    
int  p,next,val,anti;
    edge(){}
    edge(
int  a, int  b, int  c, int  d):p(a),next(b),val(c),anti(d){}
}v[maxn],e[maxm],path[maxn],arc[maxn];
int  flow[maxn],d[maxn],cnt[maxn],pre[maxn];
int  n,m,tot;
int  color[maxn];
struct  line
{
    
int  p,q;
    line(){}
    line(
int  a, int  b):p(a),q(b){}
}l[maxm];
void  init()
{
    tot 
=   0 ;
    
for ( int  i  =   0 ;i  <  n;i ++ )
    {
        v[i].next 
=   - 1 ;
        d[i] 
=   0 ;
        cnt[i] 
=   0 ;
    }
    cnt[
0 =  n;
}
void  add( int  p, int  q, int  c)
{
    e[tot] 
=  edge(q,v[p].next,c,tot  +   1 );
    v[p].next 
=  tot ++ ;
    e[tot] 
=  edge(p,v[q].next, 0 ,tot  -   1 );
    v[q].next 
=  tot ++ ;
}
int  mflow( int  s, int  t)
{
    
int  total,i,k,least,loc,now;
    
bool  flag;
    
for ( int  i  =   0 ;i  <  n;i ++ )
        arc[i].next 
=  v[i].next;
    
for (i  =  s,total  =   0 ,now  =  inf;d[i]  <  n;)
    {
        flow[i] 
=  now;
        
for (k  =  arc[i].next,flag  =   false ; ~ k;k  =  e[k].next)
        {
            
if (e[k].val  &&  d[i]  ==  d[e[k].p]  +   1 )
            {
                now 
=  min(now,e[k].val);
                pre[e[k].p] 
=  i;
                path[e[k].p].next 
=  k;
                arc[i].next 
=  k;
                i 
=  e[k].p;
                
if (i  ==  t)
                {
                    
for (total  +=  now;i  !=  s;i  =  pre[i])
                    {
                        e[path[i].next].val 
-=  now;
                        e[e[path[i].next].anti].val 
+=  now;
                    }
                    now 
=  inf;
                }
                flag 
=   true ;
                
break ;
            }
        }
        
if ( ! flag)
        {
            
for (least  =  n,k  =  v[i].next; ~ k;k  =  e[k].next)
            {
                
if (e[k].val  &&  least  >  d[e[k].p])
                {
                    least 
=  d[e[k].p];
                    loc 
=  k;
                }
            }
            arc[i].next 
=  loc;
            cnt[d[i]]
-- ;
            
if (cnt[d[i]]  ==   0 )
                
break ;
            d[i] 
=  least  +   1 ;
            cnt[d[i]]
++ ;
            
if (i  !=  s)
            {
                i 
=  pre[i];
                now 
=  flow[i];
            }
        }
    }
    
return  total;
}
int  ans;
void  dfs1( int  x)
{
    color[x] 
=   1 ;
    
for ( int  k  =  v[x].next; ~ k;k  =  e[k].next)
    {
        
if (e[k].val  &&   ! color[e[k].p])
            dfs1(e[k].p);
    }
}
void  dfs2( int  x)
{
    color[x] 
=   2 ;
    
for ( int  k  =  v[x].next; ~ k;k  =  e[k].next)
    {
        
if (e[k  ^   1 ].val  &&   ! color[e[k].p])
            dfs2(e[k].p);
    }
}
int  main()
{
    ans 
=   0 ;
    scanf(
" %d %d " , & n, & m);
    init();
    
for ( int  i  =   0 ;i  <  m;i ++ )
    {
        
int  a,b,c;
        scanf(
" %d %d %d " , & a, & b, & c);
        l[i] 
=  line(a,b);
        add(a,b,c);
    }
    mflow(
0 ,n  -   1 );
    memset(color,
0 , sizeof (color));
    dfs1(
0 );
    dfs2(n 
-   1 );
    
for ( int  i  =   0 ;i  <  m;i ++ )
    {
        
// cout << color[l[i].p] << color[l[i].q] << endl;
         if (color[l[i].p]  ==   1   &&  color[l[i].q]  ==   2 )
            ans
++ ;
    }    
    printf(
" %d\n " ,ans);
    
// cout << mflow(0,n - 1) << endl;
}

你可能感兴趣的:(ZOJ 2532 Internship && POJ 3204 Ikki's Story I - Road Reconstruction【网络流的性质,最小割中的关键边】)