【网络流】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 }