【网络流之最大流专题】解题报告
HDU 3572 Task Schedule
这种题一开始完全想不出模型,题目做多了之后就有感觉了。
对于这道题,求一次最大流,判断是否满流就可以了。
建图:添加超级源点和汇点,对于每个任务,从源点向其连一条边,权值为Pi,因为要保证每个任务做够Pi天,然后把时限区间 si ~ ei 拆成一天一天的,那么该任务对应到一天连权值为1的边,最后,对于某一天,因为有m台机器可以同时工作,那么这一天向汇点连一条边,权值为m,求最大流。
/* HDU 3549 Flow Problem */ #include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 1e9 #define eps 1e-6 #define MAXN 1005 #define MAXM 1000005 #define MODN 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; int head[MAXN], NE; int n, m; int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN]; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<n;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=n; while(dis[s]<n) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=n; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; memset(head, -1, sizeof head); } int main() { int p, s, e; int t, sum; int cas = 1; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); init(); sum = 0; int l = inf, r = -1; rep(i,1,n) { RIII(p, s, e); add_edge(0,i,p); sum += p; l = min(l, s); r = max(r, e); rep(j,s+n,e+n) add_edge(i, j, 1); } int des = 1 + r + n; rep(i,1,r) add_edge(i+n,des,m); n = des + 1; int ans = sap(0, des); printf("Case %d: %s\n\n", cas++, ans == sum ? "Yes" : "No"); } return 0; }
HDU 2883 kebab
这一题和上一题很相似,只不过 si 和 ei 的范围很大,把范围拆成一天一天很不划算。那好,既然这样,我们就拆成一个个小的区间吧,相当于把点铺在数轴上,分别取[si,ei]包含的小区间[a,b]连权值为(b-a)*M的边,当然源点汇点的建立和上一题差不多的,最后依然是判满流。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 1005 #define MAXM 8000005 #define MODN 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; struct Seg { int s, t; }A[MAXN], B[MAXN]; int head[MAXN], NE; int n, m, N; int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN]; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; memset(head, -1, sizeof head); } int L[MAXN]; int main() { int si, ni, ei, ti, k, s, t, sum; while(RII(n,m) != EOF) { init(); s = 0, t = 3*n; sum = 0; k = 0; rep(i,1,n) { scanf("%d%d%d%d", &si, &ni, &ei, &ti); A[i].s = si, A[i].t = ei; add_edge(s,i,ni*ti); sum += ni*ti; L[++k] = si; L[++k] = ei; } sort(L+1, L+k+1); rep(i,1,k-1) { B[i].s = L[i]; B[i].t = L[i+1]; add_edge(n+i, t, (B[i].t - B[i].s) * m); } rep(i,1,n) rep(j,1,k-1) if(A[i].s <= B[j].s && A[i].t >= B[j].t) add_edge(i, n+j, inf); N = t + 1; int ans = sap(s, t); printf("%s\n", ans == sum ? "Yes" : "No"); } return 0; }
HDU 3605 Escape
首先看到 n <= 100000,就知道普通的人与星球建边方法会TLE,这题m最多只有10,那么所有人的对应状态最多只有1024个,那么nn <= 100000里面会出现很多重复状态的人,那么我们可以把人的状态进行压缩、统计,之后就是从状态到星球直接连边建图判满流了。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 100015 #define MAXM 4000005 #define MODN 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; int head[MAXN], NE; int n, m, N; int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN]; int num[MAXN]; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; clr(num); memset(head, -1, sizeof head); } int main() { int c, cnt; while(RII(n, m) != EOF) { init(); cnt = 0; rep(i,1,n) { int x = 0; rep(j,1,m) { RI(c); x = (x << 1) | c; } if(!num[x]) cnt++; num[x]++; } int k = cnt; int t = 1+k+m; rep(i,1,m) { RI(c); add_edge(cnt+i,t,c); } cnt = 0; rep(i,0,1024) { if(!num[i]) continue; add_edge(0, ++cnt, num[i]); rep(j,1,m) { if((i>>(j-1))&1) add_edge(cnt, k+j, num[i]); } } N = t+1; int ans = sap(0, t); if(ans == n) puts("YES"); else puts("NO"); } return 0; }
HDU 4183 Pahom on Water
由于除了起点和终点外,其他的结点在访问一次之后就不可再利用了,对于这种情况,不难想到要对每个结点进行拆点,在拆成的连点之间连一条容量为1的边i->i',就可以保证只访问一次(这种化点为边的思想在网络流里很重要),题目要求从起点到终点再从终点到起点的过程可以转化为判断能否从起点开始,有两条不重复的路径到达终点,显然,超级源点到起点间连一条容量为2的边s->i,然后从终点拆点到汇点也连一条容量为2的边i'->t,中间可以跳跃的点之间连容量>=1的边i'->j,最后求最大流看是否满流。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 1005 #define MAXM 1000005 #define MOD 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; struct Node { double Mz; int x, y, r; }A[MAXN]; int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN]; int n, m, N; int head[MAXN], NE; bool g[MAXN][MAXN]; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; clr(g); memset(head, -1, sizeof head); } double dist(Node q, Node p) { return (q.x - p.x) * (q.x - p.x) + (q.y - p.y) * (q.y - p.y); } int main() { int cas, s, t; double a; int b, c, d; RI(cas); while(cas--) { RI(n); init(); s = 2 * n + 1, t = 2 * n + 2; rep(i,1,n) { scanf("%lf%d%d%d", &a, &b, &c, &d); A[i].Mz = a, A[i].x = b, A[i].y = c, A[i].r = d; } for(int i = 1; i <= n; i++) { add_edge(i, i+n, 1); for(int j = 1; j<=n; j++) if(A[i].Mz < A[j].Mz && dist(A[i], A[j]) < (A[i].r + A[j].r) * (A[i].r + A[j].r)) add_edge(i+n, j, 1); if(A[i].Mz == 400.0) add_edge(s, i+n, 2); else if(A[i].Mz == 789.0) add_edge(i, t, 2); } N = 2 + n*2; int ans = sap(s, t); if(ans < 2) puts("Game is NOT VALID"); else puts("Game is VALID"); } return 0; }
HDU 4240 Route Redundancy
这道题题意很明确,二分最短路+最大流,属于简单题。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 1005 #define MAXM 200005 #define MOD 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM], E1[MAXM]; // edge list int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN]; int n, m; int head[MAXN], NE; int d[MAXN]; bool vis[MAXN]; void addedge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<n;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=n; while(dis[s]<n) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=n; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void spfa(int s, int val) { queue<int> que; memset(d, 0x3f, sizeof d); memset(vis, false, sizeof vis); d[s] = 0; vis[s] = true; que.push(s); while(!que.empty()) { int u = que.front(); que.pop(); vis[u] = false; for(int i = head[u]; i != -1; i = E1[i].next) { int nx = E1[i].v; int cost = E1[i].w; if(d[u] + cost < d[nx] && cost >= val) { d[nx] = d[u] + cost; if(!vis[nx]) { vis[nx] = true; que.push(nx); } } } } } void init() { NE = 0; memset(head, -1, sizeof head); } int main() { int cas, s, t, id; int u, v, w; RI(cas); while(cas--) { scanf("%d%d%d%d%d", &id, &n, &m, &s, &t); init(); int l = inf, r = -1; rep(i,1,m) { RIII(u, v, w); addedge(u, v, w); r = max(r, w); l = min(l, w); } memcpy(E1, E, sizeof E); int maxflow = sap(s, t); while(l <= r) { int mid = (l + r) >> 1; spfa(s, mid); if(d[t] < inf) l = mid + 1; else r = mid - 1; } printf("%d %.3lf\n", id, maxflow*1.0/(l-1)); } return 0; }
HDU 3081 Marriage Match II
二分最大流。
建边的时候用到并查集,因为女孩会根据她的女性朋友和男孩之间的是否吵过架连边。超级源点和女孩之间连边,权值为二分值;男孩和超级汇点之间连边,权值也是二分值,二分判断最大流是否满流即可。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 505 #define MAXM 1000005 #define MOD 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; struct Node { int x, y; }a[MAXM]; int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN]; int n, m, N; int head[MAXN], NE; int f[MAXN]; bool g[MAXN][MAXN]; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; clr(g); memset(head, -1, sizeof head); } int find(int x) { return f[x] == x ? f[x] : f[x] = find(f[x]); } void union_set(int u, int v) { int x = find(u); int y = find(v); f[x] = y; } void build(int s, int t, int v) { init(); rep(i,1,n) { add_edge(s, i, v); add_edge(n+i, t, v); } rep(i,1,m) { rep(j,1,n) { if(find(j) == find(a[i].x) && !g[j][a[i].y]) { g[j][a[i].y] = true; add_edge(j, n+a[i].y, 1); } } } } int main() { int cas, s, t, F, u, v; RI(cas); while(cas--) { RIII(n, m, F); s = 0, t = 2*n+1; rep(i,0,n) f[i] = i; rep(i,1,m) RII(a[i].x, a[i].y); rep(i,1,F) { RII(u, v); union_set(u, v); } N = t+1; int l = 0, r = n; int ans = 0; while(l <= r) { int mid = (l + r) >> 1; build(s, t, mid); if(sap(s,t) == n * mid) { ans = mid; l = mid + 1; } else r = mid - 1; } printf("%d\n", ans); } return 0; }
HDU 3277 Marriage Match III
这道题和上一道题HDU 3081一样都是二分最大流,这题多了一点“ in order to play more times of marriage match, every girl can accept any K boys”,解决这个问题的做法是把女孩进行拆点,边权为K。对于某个女孩,和吵过架的男孩连一条边i'->j,权值为1。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 1005 #define MAXM 5000005 #define MOD 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; struct Node { int x, y; }a[MAXM]; int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN]; int n, m, k, N; int head[MAXN], NE; int f[MAXN]; bool g[MAXN][MAXN]; int low; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { clr(dis); clr(gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; memset(head, -1, sizeof head); } int find(int x) { return f[x] == x ? f[x] : f[x] = find(f[x]); } void union_set(int u, int v) { int x = find(u); int y = find(v); f[x] = y; } void build(int s, int t, int v) { init(); rep(i,1,n) { add_edge(s, i, v); add_edge(2*n+i, t, v); } rep(i,1,n) add_edge(i, i+n, k); rep(i,1,n) { rep(j,1,n) { if(g[i][j]) add_edge(i, 2*n+j, 1); else add_edge(i+n, 2*n+j, 1); } } } int main() { int cas, s, t, F, u, v; RI(cas); while(cas--) { scanf("%d%d%d%d", &n, &m, &k, &F); s = 0, t = 3*n+1; rep(i,0,n) f[i] = i; rep(i,1,m) RII(a[i].x, a[i].y); rep(i,1,F) { RII(u, v); union_set(u, v); } clr(g); rep(i,1,m) g[find(a[i].x)][a[i].y] = true; rep(i,1,n) rep(j,1,n) if(g[find(i)][j]) g[i][j] = true; N = t+1; int l = 0, r = n; int ans = 0; while(l <= r) { int mid = (l + r) >> 1; build(s, t, mid); if(sap(s, t) == n * mid) { ans = mid; l = mid + 1; } else r = mid - 1; } printf("%d\n", ans); } return 0; }
HDU 2485 Destroying the bus stations
这道题很明显用最小费用最大流。
拆点后,每一次求最短路可以除掉一条边,也就是去掉一个station,一直求最短路直到大于K为止,所统计的流量就是所求。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cstring> #include <ctime> #include <queue> #include <cassert> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf (0x3f3f3f3f) #define eps 1e-6 #define MAXN 1005 #define MAXM 4000005 #define MODN 1000000007 #define RI(x) scanf("%d", &x) #define RII(x,y) scanf("%d%d", &x, &y) #define RIII(x,y,z) scanf("%d%d%d", &x, &y, &z) #define debug puts("reach here"); typedef long long LL; struct Edge { int to; int vol; int cost; int next; }E[MAXM]; int index[MAXN]; int NE; int pre[MAXN], pos[MAXN]; int dis[MAXN], que[MAXM]; bool vis[MAXN]; int n, m, k; void insert(int from, int to, int vol, int cost) { E[NE].to = to; E[NE].vol = vol; E[NE].cost = cost; E[NE].next = index[from]; index[from] = NE++; E[NE].to = from; E[NE].vol = 0; E[NE].cost = -cost; E[NE].next = index[to]; index[to] = NE++; } bool spfa(int s, int t) { memset(pre, -1, sizeof(pre)); memset(vis, 0, sizeof(vis)); int head, tail; head = tail = 0; memset(dis, 0x3f, sizeof dis); que[tail++] = s; pre[s] = s; dis[s] = 0; vis[s] = 1; while(head != tail) { int cur = que[head++]; vis[cur] = 0; for(int i = index[cur]; i != -1; i = E[i].next) { int adj = E[i].to; if(E[i].vol > 0 && dis[cur] + E[i].cost < dis[adj]) { dis[adj] = dis[cur] + E[i].cost; pre[adj] = cur; pos[adj] = i; if(!vis[adj]) { vis[adj] = 1; que[tail++] = adj; } } } } return pre[t] != -1; } int MinCostMaxFlow(int s, int t) { int cost = 0; int flow = 0; while(spfa(s, t)) { if(dis[t] > k) return flow; int f = inf; for(int i = t; i != s; i = pre[i]) if (E[pos[i]].vol < f) f = E[pos[i]].vol; flow += f; cost += dis[t] * f; for(int i = t; i != s; i = pre[i]) { E[pos[i]].vol -= f; E[pos[i] ^ 1].vol += f; } } return flow; } void init() { NE = 0; memset(index, -1, sizeof index); } int main() { int a, b; while(RIII(n, m, k) != EOF) { if(n==0 && m==0 && k==0) break; init(); rep(i,0,n-1) insert(i<<1, i<<1|1, 1, 0); rep(i,0,m-1) { RII(a, b); a--, b--; insert(a<<1|1, b<<1, 1, 1); } printf("%d\n", MinCostMaxFlow(1, (n-1)<<1)); } }
HDU 3468 Treasure Hunting
一开始没看出来是网络流,一直往搜索的思路想。
题意理解也略微蛋疼,这个解题报告写得不错。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 20005 #define MAXM 5000005 #define MOD 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; struct Node { int x, y, cnt; }; int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN]; int n, m, N, k, c; int head[MAXN], NE; char g[101][101]; int dr[4][2] = {{0,1}, {0,-1}, {1,0}, {-1, 0}}; int d[55][MAXN]; int tot; int to[55]; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } bool isOut(int xx, int yy) { return !(xx >= 0 && xx < m && yy >= 0 && yy < n); } int getID(char c) { return islower(c) ? c - 'a' + 26 : c-'A'; } void getRalCnt() { tot = 0; rep(i,0,n-1) { rep(j,0,m-1) { if(isalpha(g[i][j])) tot++; } } } bool bfs(int y, int x, int id) { queue<Node> que; Node tmp; int cnt = 1; tmp.x = x, tmp.y = y, tmp.cnt = 0; que.push(tmp); d[id][y*m+x] = 0; while(!que.empty()) { Node cur = que.front(); que.pop(); int cx = cur.x; int cy = cur.y; int cc = cur.cnt; rep(i,0,3) { int xx = cx + dr[i][0]; int yy = cy + dr[i][1]; if(!isOut(xx,yy) && g[yy][xx] != '#' && d[id][yy*m+xx] == -1) { tmp.x = xx, tmp.y = yy, tmp.cnt = cc + 1; d[id][yy*m+xx] = cc + 1; que.push(tmp); if(isalpha(g[yy][xx])) { cnt++; if(getID(g[yy][xx]) == id + 1) to[id] = cc + 1; } } } } return cnt == tot; } void init() { NE = 0; memset(head, -1, sizeof head); } void build() { int goldCnt = tot+1; init(); rep(i,0,n-1) { rep(j,0,m-1) { if(g[i][j] == '*') { rep(k,0,tot-2) { if(d[k][i*m+j] + d[k+1][i*m+j] == to[k]) add_edge(k+1, goldCnt, 1); } } goldCnt++; } } rep(i,1,tot-1) add_edge(0, i, 1); rep(i,tot+1,goldCnt-1) add_edge(i, tot, 1); N = goldCnt; } bool calDis() { memset(d, -1, sizeof d); getRalCnt(); rep(i,0,n-1) rep(j,0,m-1) if(isalpha(g[i][j])) if(!bfs(i,j,getID(g[i][j]))) return false; return true; } int main() { while(RII(n, m) != EOF) { rep(i,0,n-1) scanf("%s", g[i]); if(!calDis()) { puts("-1"); continue; } build(); printf("%d\n", sap(0, tot)); } return 0; }
HDU 4309 Seikimatsu Occult Tonneru
因为桥最多有12条,所以直接2^12枚举修复的桥。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 1005 #define MAXM 5000005 #define MOD 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; struct Node { int a, b, c, d; }A[MAXM]; int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN]; int n, m, k, N; int head[MAXN], NE; int num[MAXN]; int cid[MAXM], cnt; bool vis[MAXN]; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { clr(dis); clr(gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; memset(head, -1, sizeof head); } int main() { int tot; while(RII(n, m) != EOF) { int s = 0, t = n+1; init(); cnt = 0; tot = 0; memset(cid, -1, sizeof cid); rep(i,1,n) { RI(num[i]); add_edge(s, i, num[i]); } rep(i,1,m) { scanf("%d%d%d%d", &A[i].a, &A[i].b, &A[i].c, &A[i].d); if(A[i].d > 0) { cid[i] = cnt++; tot += A[i].c; } if(A[i].d < 0) add_edge(A[i].a, t, A[i].c); add_edge(A[i].a, A[i].b, inf); } N = n + 2; int maxFlow = sap(s, t); if(maxFlow == 0) { puts("Poor Heaven Empire"); continue; } //printf("%d\n", ans); int cost; int ans = tot; rep(i,0,(1<<cnt)-1) { init(); cost = 0; rep(j,1,n) add_edge(s, j, num[j]); rep(j,1,m) { if(cid[j] >= 0) { if(i & (1 << cid[j])) // fix the road { add_edge(A[j].a, A[j].b, inf); cost += A[j].c; } else // not fix add_edge(A[j].a, A[j].b, 1); } else { if(A[j].d < 0) add_edge(A[j].a, t, A[j].c); add_edge(A[j].a, A[j].b, inf); } } int tmp = sap(s, t); if(tmp == maxFlow) ans = min(ans, cost); } printf("%d %d\n", maxFlow, ans); } return 0; }
POJ 3281 Dining
很不错的一道题,对牛进行拆点,容量为1,建图顺序为:超级源点 -> 食物 -> 牛 -> 饮料 -> 超级汇点,这样想通之后应该就不难做了。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 1e9 #define eps 1e-6 #define MAXN 505 #define MAXM 10000005 #define MODN 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; int head[MAXN], NE; int n, m, k, N; int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN]; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; memset(head, -1, sizeof head); } int main() { int f, d, a, b, s, t, k1, k2; while(RIII(n,f,d) != EOF) { init(); s = 0, t = f + d + 2*n + 1; rep(i,1,f) add_edge(s, i, 1); rep(i,1,d) add_edge(f+2*n+i, t, 1); rep(i,f+1, f+n) add_edge(i,i+n,1); rep(i,1,n) { RII(k1,k2); rep(x,1,k1) { RI(a); add_edge(a, f+i, 1); } rep(x,1,k2) { RI(b); add_edge(f+n+i, f+2*n+b,1); } } N = t+1; printf("%d\n", sap(s, t)); } return 0; }
POJ 2112 Optimal Milking
floyd求一下最短路,然后二分距离建图求最大流,判断是否满流。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 505 #define MAXM 1000005 #define MOD 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN]; int n, m, N, k, c; int head[MAXN], NE; int d[MAXN][MAXN]; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; memset(head, -1, sizeof head); } void build(int v) { init(); int s = 0, t = k + c + 1; rep(i,1,c) add_edge(s, k+i, 1); rep(i,1,k) add_edge(i, t, m); rep(i,k+1,k+c) rep(j,1,k) if(d[i][j] <= v) add_edge(i, j, 1); } int main() { int maxd; while(RIII(k,c,m) != EOF) { maxd = 0; rep(i,1,k+c) rep(j,1,k+c) { RI(d[i][j]); if(d[i][j] == 0) d[i][j] = inf; } rep(p,1,k+c) rep(i,1,k+c) rep(j,1,k+c) d[i][j] = min(d[i][j], d[i][p] + d[p][j]); rep(i,1,k+c) rep(j,1,k+c) if(d[i][j] < inf) maxd = max(maxd, d[i][j]); int l = 0, r = maxd; N = k+c + 2; int ans = 0; while(l <= r) { int mid = (l + r) >> 1; build(mid); if(sap(0, k+c+1) == c) { r = mid - 1; ans = mid; } else l = mid + 1; } printf("%d\n", ans); } return 0; }
POJ 2289 Jamie's Contact Groups
还是二分最大流。不说了,说多了都是泪。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 2005 #define MAXM 5000005 #define MOD 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN]; int n, m, N, k, c; int head[MAXN], NE; bool g[MAXN][MAXN]; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; memset(head, -1, sizeof head); } void build(int s, int t, int v) { init(); rep(i,1,n) add_edge(s, i, 1); rep(i,1,n) rep(j,n+1,n+m) if(g[i][j]) add_edge(i,j,1); rep(i,n+1,n+m) add_edge(i,t,v); } int main() { char s[20]; int a; while(RII(n, m) != EOF) { if(n == 0 && m == 0) break; clr(g); rep(i,1,n) { scanf("%s", s); while(getchar() == ' ') { scanf("%d", &a); g[i][n+1+a] = true; } } N = 2 + n + m; int src = 0, des = N-1; int l = 0, r = n; int ans = 0; while(l <= r) { int mid = (l + r) >> 1; build(src, des, mid); if(sap(src, des) == n) { r = mid - 1; ans = mid; } else l = mid + 1; } printf("%d\n", ans); } return 0; }
POJ 3498 March of the Penguins
枚举终点,每个点i拆点,边容量为mi,超级源点连一条边到每个点,容量分别为ni,对于可以相互跳跃到达的顶点,连一条边i'->j,容量为无穷大,统计一共有多少个点作为终点可以满流。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 205 #define MAXM 500005 #define MOD 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; struct Node { double x, y; int ni,mi; }a[MAXN]; int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN]; int n, m, N; int head[MAXN], NE; double D; bool g[101][101]; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; memset(head, -1, sizeof head); } int ans[105]; void build(int s, int t, int id) { init(); rep(i,0,n-1) { add_edge(i, i+n, a[i].mi); add_edge(s, i, a[i].ni); } rep(i,0,n-1) { rep(j,0,n-1) { if(i == j) continue; if(g[i][j]) add_edge(i+n, j, inf); } } } int main() { int cas, sum; RI(cas); while(cas--) { scanf("%d%lf", &n, &D); sum = 0; rep(i,0,n-1) { scanf("%lf%lf%d%d", &a[i].x, &a[i].y, &a[i].ni, &a[i].mi); sum += a[i].ni; } clr(g); rep(i,0,n-1) { rep(j,0,n-1) { if(D * D >= (a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y)) g[i][j] = true; } } int cnt = 0; int s = 2*n, t = 2*n+1; N = 2*n + 2; rep(i,0,n-1) { build(s, i, i); if(sap(s, i) == sum) ans[cnt++] = i; } if(cnt == 0) puts("-1"); else { rep(i,0,cnt-1) printf("%d%c", ans[i], i == cnt-1 ? '\n' : ' '); } } return 0; }
POJ 3228 Gold Transportation
题目要求在满流的情况下的一个最长路径最短的方案,明显二分最大流。
#include <vector> #include <list> #include <map> #include <set> #include <queue> #include <deque> #include <stack> #include <algorithm> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <queue> using namespace std; #define pii pair<int,int> #define clr(a) memset((a),0,sizeof (a)) #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) #define inf 0x3f3f3f3f #define eps 1e-6 #define MAXN 505 #define MAXM 1000005 #define MOD 1000000007 #define debug puts("reach here") #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&x) #define RII(x,y) scanf("%d%d",&x,&y) #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) typedef long long LL; struct Edge { int v, w, next; }E[MAXM]; struct Node { int u, v, w; }e[MAXM]; int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN]; int n, m, N; int head[MAXN], NE; void add_edge (int u, int v, int w) { E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; } inline void checkmin(int &a,int b) {if(a == -1 || a > b)a = b;} int sap(int s,int t) { memset(dis,0,sizeof dis); memset(gap,0,sizeof gap); for(int i=0;i<N;++i) cur[i]=head[i]; int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=N; while(dis[s]<N) { loop:for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { checkmin(aug,E[i].w); pre[v]=u; u=v; if(v==t) { maxflow+=aug; for(u=pre[u];v!=s;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=-1; } goto loop; } } int mindis=N; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mindis>dis[v]) { cur[u]=i; mindis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } void init() { NE = 0; memset(head, -1, sizeof head); } int a[MAXN], b[MAXN]; void build(int s, int t, int v) { init(); rep(i,1,n) { add_edge(s, i, a[i]); add_edge(i, t, b[i]); } rep(i,1,m) if(e[i].w <= v) { add_edge(e[i].u, e[i].v, inf); add_edge(e[i].v, e[i].u, inf); } } int main() { int sum; while(RI(n) != EOF && n) { rep(i,1,n) RI(a[i]); rep(i,1,n) RI(b[i]); sum = 0; rep(i,1,n) sum += a[i]; RI(m); rep(i,1,m) { RIII(e[i].u, e[i].v, e[i].w); } int l = 0, r = 10001; N = n + 2; int ans = -1; int s = 0, t = n + 1; while(l <= r) { int mid = (l + r) >> 1; build(s, t, mid); if(sap(s, t) == sum) { r = mid - 1; ans = mid; } else l = mid + 1; } if(ans == -1) puts("No Solution"); else printf("%d\n", ans); } return 0; }