【网络流】poj 3821 Destroying the bus stations -北京2008

http://poj.org/problem?id=3921

   题目给出一个有向图,询问从2~n-1这些点中最少删除几个使得新图中1到n的不存在长度小于等于K的路径。

   首先对原图先进行一遍预处理,删除对答案没有影响的边,对于边s->t,如果1到s的最短路长度 dis[0][s] + t到n的最短路长度dis[1][t] >= K , 则s-->t这条边不会对答案造成任何影响,因为经过这条边的联通1和n的路径长度最短为K+1. 我们首先将这类边删除。

   再对新图进行讨论可以发现,显然有新图中存在1~n的联通路径 与原问题是等价的。到这里我们得到最终算法,将新图中每个点拆成两个一个入一个出,并在其间连一条权值为1的有向路径,再求最小割即可。

 注:该算法已经被证明是错误的,数据如下

8 10 5
1 2
2 3
3 4
4 5
5 6
6 8
1 7
7 8
4 7
7 4
正确答案应该为1.
貌似算法证明在环上是不成立的! 正确做法只有搜索
View Code
  1 //By Lin
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<queue>
  5 #define Rep(i,n) for(int i = 0; i<n; i++)
  6 using namespace std;
  7 
  8 #define N 155
  9 #define M 8010
 10 int        ecnt;
 11 struct    Edge{
 12     int to,num,w;
 13     Edge *next;
 14 }*mat[N*2],*cur[N*2],edges[M*2+N*2];
 15 void    link(int x,int to ){
 16     edges[ecnt].to = to;
 17     edges[ecnt].next = mat[x];
 18     mat[x] = &edges[ecnt++];
 19 }
 20 void    link(int x,int to , bool flag ) {
 21     edges[ecnt].to = to;
 22     edges[ecnt].num= ecnt;
 23     edges[ecnt].w  = 1;
 24     edges[ecnt].next = mat[x];
 25     mat[x] = &edges[ecnt++];
 26 
 27     edges[ecnt].to = x;
 28     edges[ecnt].num= ecnt;
 29     edges[ecnt].w  = 0;
 30     edges[ecnt].next = mat[to];
 31     mat[to] = &edges[ecnt++];
 32 }
 33 
 34 int        n,m,K;
 35 int        dis[2][N],input[M][2];
 36 
 37 void    spfa(int st,int dis[] ){
 38     for (int i = 1; i<=n; i++) dis[i] = K+10;
 39     dis[st] = 0;
 40     queue<int> que;
 41     que.push(st);
 42     while ( !que.empty() ) {
 43         int i = que.front(); que.pop();
 44         for ( Edge *p = mat[i]; p; p = p->next ){
 45             int to = p->to;
 46             if ( dis[to] > dis[i]+1 ) {
 47                 dis[to] = dis[i]+1;
 48                 que.push(to); 
 49             }
 50         }
 51     }
 52 }
 53 
 54 int        remit , source; 
 55 int        lev[N*2], stack[N*2], top, ff;
 56 int        from[N*2];
 57 bool    bfs(){
 58     memset( lev , -1 , sizeof(lev) );
 59     lev[source] = 0;
 60     queue<int> que;
 61     while ( !que.empty() ) que.pop();
 62     que.push( source );
 63     while ( !que.empty() ) {
 64         int i = que.front(); que.pop();
 65         for ( Edge *p = mat[i]; p; p = p->next ){
 66             int to = p->to;
 67             if ( p->w == 0 || lev[to] != -1 ) continue;
 68             lev[to] = lev[i]+1;
 69             que.push(to);
 70             if ( to == remit ) return true;
 71         }
 72     }
 73     return false;
 74 }
 75 
 76 void    dfs(){
 77     top = 1;
 78     stack[0] = source;
 79     memcpy( cur , mat , sizeof(cur) );
 80     while ( top ) {
 81         int i = stack[top-1];
 82         if ( i == remit ) {
 83             for (int i = 1; i<top; i++){
 84                 edges[from[stack[i]]].w --;
 85                 edges[from[stack[i]]^1].w ++;
 86             }
 87             top = 1;
 88             ff++;
 89         }
 90         else{
 91             for ( ; cur[i] ; cur[i] = cur[i]->next )
 92                 if ( lev[cur[i]->to] == lev[i]+1 && cur[i]->w ) break;
 93             if ( cur[i] ) {
 94                 stack[top++] = cur[i]->to;
 95                 from[cur[i]->to] = cur[i]->num;
 96             }
 97             else {
 98                 lev[i] = -1;
 99                 top--;
100             }
101         }
102     }
103 }
104 
105 int        main(){
106     while ( ~scanf("%d%d%d", &n, &m, &K ) ) {
107         if ( n == 0 && m == 0 && K == 0 ) break;
108         Rep(i,m) scanf("%d%d", &input[i][0], &input[i][1] );
109         ecnt = 0;
110         memset( mat , 0 , sizeof(mat) );
111         Rep(i,m) link( input[i][0], input[i][1] );
112         spfa( 1 , dis[0] );
113         ecnt = 0;
114         memset( mat , 0 , sizeof(mat) );
115         Rep(i,m) link( input[i][1], input[i][0] );
116         spfa( n , dis[1] );
117 
118         ecnt = 0;
119         memset( mat , 0 , sizeof(mat) );
120         for (int i = 1; i<=n; i++) link( i*2-1 , i*2 , 1 );
121         Rep(i,m) {
122             if ( dis[0][input[i][0]] + dis[1][input[i][1]] >= K ) continue;
123             link( input[i][0]*2 , input[i][1]*2-1 , 1 );
124         }
125 
126         ff = 0; 
127         source = 2;
128         remit = n*2-1;
129         while ( bfs() ) dfs();
130         printf("%d\n" , ff );
131     }
132     return 0;
133 }

 

转载于:https://www.cnblogs.com/lzqxh/archive/2013/02/17/2914341.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值