Time Limit: 2000MS | Memory Limit: 32768K | |
Total Submissions: 24019 | Accepted: 12540 |
Description

An example is in figure 1. The label x/y of power station u shows that p(u)=x and p max(u)=y. The label x/y of consumer u shows that c(u)=x and c max(u)=y. The label x/y of power transport line (u,v) shows that l(u,v)=x and l max(u,v)=y. The power consumed is Con=6. Notice that there are other possible states of the network but the value of Con cannot exceed 6.
Input
Output
Sample Input
2 1 1 2 (0,1)20 (1,0)10 (0)15 (1)20 7 2 3 13 (0,0)1 (0,1)2 (0,2)5 (1,0)1 (1,2)8 (2,3)1 (2,4)7 (3,5)2 (3,6)5 (4,2)7 (4,3)5 (4,5)1 (6,0)5 (0)5 (1)2 (3)2 (4)1 (5)4
Sample Output
15 6
Hint
Source


1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 #define MAXN 202 6 const int INT_MAX = 0x3f3f3f3f ; 7 int s, t; 8 int n, np, nc, m; 9 char str[50]; 10 int c[MAXN][MAXN]; 11 int f[MAXN][MAXN]; 12 int e[MAXN]; 13 int h[MAXN]; 14 void push(int u, int v) 15 { 16 int d = min(e[u], c[u][v] - f[u][v]); 17 f[u][v] += d; 18 f[v][u] = -f[u][v]; 19 e[u] -= d; 20 e[v] += d; 21 } 22 bool relabel(int u) 23 { 24 int mh = INT_MAX; 25 for(int i=0; i<n+2; i++) 26 { 27 if(c[u][i] > f[u][i]) 28 mh = min(mh, h[i]); 29 } 30 if(mh == INT_MAX) 31 return false; //残留网络中无从u出发的路 32 h[u] = mh + 1; 33 for(int i=0; i<n+2; i++) 34 { 35 if(e[u] == 0) //已无余流,不需再次push 36 break; 37 if(h[i] == mh && c[u][i] > f[u][i]) //push的条件 38 push(u, i); 39 } 40 return true; 41 } 42 void init_preflow() 43 { 44 memset(h, 0, sizeof(h)); 45 memset(e, 0, sizeof(e)); 46 h[s] = n+2; 47 for(int i=0; i<n+2; i++) 48 { 49 if(c[s][i] == 0) 50 continue; 51 f[s][i] = c[s][i]; 52 f[i][s] = -f[s][i]; 53 e[i] = c[s][i]; 54 e[s] -= c[s][i]; 55 } 56 } 57 void push_relabel() 58 { 59 init_preflow(); 60 bool flag = true; //表示是否还有relabel操作 61 while(flag) 62 { 63 flag = false; 64 for(int i=0; i<n; i++) 65 if(e[i] > 0) 66 flag = flag || relabel(i); 67 } 68 } 69 int main() 70 { 71 while(scanf("%d%d%d%d", &n, &np, &nc, &m) != EOF) 72 { 73 s = n; t = n+1; 74 memset(c, 0, sizeof(c)); 75 memset(f, 0, sizeof(f)); 76 while(m--) 77 { 78 scanf("%s", &str); 79 int u=0, v=0, z=0; 80 sscanf(str, "(%d,%d)%d", &u, &v, &z); 81 c[u][v] = z; 82 } 83 for(int i=0; i<np+nc; i++) 84 { 85 scanf("%s", &str); 86 int u=0, z=0; 87 sscanf(str, "(%d)%d", &u, &z); 88 if(i < np) 89 c[s][u] = z; 90 else if(i >= np && i < np + nc) 91 c[u][t] = z; 92 } 93 push_relabel(); 94 printf("%d\n", e[t]); 95 } 96 }
dinic递归 110ms / 非递归 110 或 94 ms:http://hefeijack.iteye.com/blog/1885944
dinic 63ms/SAP 63 ms:http://www.cnblogs.com/kuangbin/archive/2012/09/11/2680908.html
dinic 63ms :http://blog.youkuaiyun.com/u011721440/article/details/38611197
初学者可以先去poj1273试试水=。=
这道题只要加一个 源点 和 汇点 , 就万事大吉了。
自己写了一遍,用dinic的递归形式,一开始tle,但就加了一句话,813msAC,
貌似是一种优化,但为啥不清楚。


1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 const int M = 210 , inf = 0x3f3f3f3f ; 7 int m , n ; 8 int map[M][M] ; 9 int dis[M]; 10 11 bool bfs () 12 { 13 queue <int> q ; 14 while (!q.empty ()) 15 q.pop () ; 16 memset (dis , 0xff , sizeof(dis)) ; 17 dis[1] = 0 ; 18 q.push (1) ; 19 while (!q.empty () ) { 20 int u = q.front () ; 21 q.pop () ; 22 for (int v = 1 ; v <= n ; v++) { 23 if (map[u][v] && dis[v] == -1) { 24 dis[v] = dis[u] + 1 ; 25 q.push (v) ; 26 } 27 } 28 } 29 if (dis[n] > 0) 30 return true ; 31 return false ; 32 } 33 34 int find (int u , int low) 35 { 36 int a = 0 ; 37 if (u == n) 38 return low ; 39 for (int v = 1 ; v <= n ; v++) { 40 if (map[u][v] && dis[v] == dis[u] + 1 && (a = find (v , min(map[u][v] , low)))) { 41 map[u][v] -= a ; 42 map[v][u] += a ; 43 return a ; 44 } 45 } 46 dis[u] = -1 ;//就这句 47 return 0 ; 48 } 49 50 int main () 51 { 52 //freopen ("b.txt" , "r" , stdin) ; 53 int u , v , w ; 54 int ans ; 55 while (~ scanf ("%d%d" , &m , &n)) { 56 memset (map , 0 , sizeof(map)) ; 57 while (m--) { 58 scanf ("%d%d%d" , &u , &v , &w) ; 59 map[u][v] += w ; 60 } 61 int maxn = 0 ; 62 while (bfs()) { 63 if (ans = find(1 , inf)) 64 maxn += ans ; 65 } 66 printf ("%d\n" , maxn) ; 67 } 68 return 0 ; 69 }
用邻接表可以进一步优化(但上面那句话仍要加):因为用矩阵的话在find 和 bfs 时找点都要遍历一遍所有的点,但用邻接表的话可以很快找到。
110msAC:


1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 const int M = 110 , inf = 0x3f3f3f3f ; 7 struct edge 8 { 9 int u , v , time_u ; 10 int w ; 11 }e[M * M * 2]; 12 int n , np , nc , m ; 13 int src , des ; 14 int cnt = 0 ; 15 int dis[M] ; 16 char st[200] ; 17 int head[M * M * 2] ; 18 19 void addedge (int u , int v , int w) 20 { 21 e[cnt].u = u ; e[cnt].v = v ; e[cnt].w = w ; e[cnt].time_u = head[u] ; 22 head[u] = cnt++ ; 23 e[cnt].v = u ; e[cnt].u = v ; e[cnt].w = 0 ; e[cnt].time_u = head[v] ; 24 head[v] = cnt++ ; 25 } 26 bool bfs () 27 { 28 queue <int> q ; 29 while (!q.empty ()) 30 q.pop () ; 31 memset (dis , -1 , sizeof(dis)) ; 32 dis[src] = 0 ; 33 q.push (src) ; 34 while (!q.empty ()) { 35 int u = q.front () ; 36 q.pop () ; 37 for (int i = head[u] ; i != -1 ; i = e[i].time_u) { 38 int v = e[i].v ; 39 if (dis[v] == -1 && e[i].w > 0) { 40 dis[v] = dis[u] + 1 ; 41 q.push (v) ; 42 } 43 } 44 } 45 if (dis[des] > 0) 46 return true ; 47 return false ; 48 } 49 50 int find (int u , int low) 51 { 52 int a = 0 ; 53 if (u == des) 54 return low ; 55 for (int i = head[u] ; i != -1 ; i = e[i].time_u) { 56 int v = e[i].v ; 57 if (e[i].w > 0 && dis[v] == dis[u] + 1 && (a = find(v , min (low , e[i].w)))) { 58 e[i].w -= a ; 59 e[i^1].w += a ; 60 return a ; 61 } 62 } 63 dis[u] = -1 ; 64 return false ; 65 } 66 67 int main () 68 { 69 // freopen ("a.txt" , "r" , stdin) ; 70 int u , v , w ; 71 while (~ scanf ("%d%d%d%d" , &n , &np , &nc , &m)) { 72 src = n ; 73 des = n + 1 ; 74 cnt = 0 ; 75 memset (head , -1 , sizeof(head)) ; 76 while (m--) { 77 scanf ("%s" , st) ; 78 sscanf (st , "(%d,%d)%d" , &u , &v , &w) ; 79 addedge(u , v , w) ; 80 } 81 while (np--) { 82 scanf ("%s" , st) ; 83 sscanf (st , "(%d)%d" , &v , &w) ; 84 addedge (src , v , w) ; 85 } 86 while (nc--) { 87 scanf ("%s" , st) ; 88 sscanf (st , "(%d)%d" , &u , &w) ; 89 addedge (u , des , w) ; 90 } 91 92 int ans = 0 , res = 0 ; 93 while (bfs()) { 94 while (1) { 95 if (ans = find(src , inf)) 96 res += ans ; 97 else 98 break ; 99 } 100 } 101 printf ("%d\n" , res) ; 102 } 103 return 0 ; 104 }
head[u]用来存放点u最新出现的时间 ,感觉和tarjan算法中的dfn[u]差不多;
time_u则保存上一次点u出现的时间 。