hdu 2485 Destroying the bus stations
第一次接触这类问题,最小费用最大流的关键是如何建图,其次就是套模板。这题借鉴了别人的方法:由于图中的两个节点间可能互有通路,所以将一个点拆分成两个,分别表示入和出。绝大多数模板中都是不断求源端到汇点的最小费用路径然后扩增。因此,将每次扩增等于删除流量最小段所代表的点。直到源点到汇点的最小费用大于k#include<cstdio> #include<algorithm> #include<vector> #include<cmath> #include<set> #pragma comment(linker, "/STACK:1024000000,1024000000") // acm.hdu.edu.cn/showproblem.php?pid=4494 using namespace std; #define MAXN 105 int n, m, k; struct _node { int to, next, cost, val; _node(int a, int b, int c, int d): to(a),next(b),cost(c),val(d) {} _node() {} }ee[MAXN*MAXN]; int head[MAXN], cnt; int end ; void add(int u, int v, int cost, int val) { ee[cnt] = _node(v, head[u], cost, val); head[u] = cnt++; ee[cnt] = _node(u, head[v], -cost, 0); head[v] = cnt++; } int q[MAXN*MAXN], vis[MAXN], dis[MAXN], fa[MAXN]; int pos[MAXN]; int spfa() { int bg = 0, ed = 0; memset(vis, 0, sizeof vis); memset(fa, -1, sizeof fa); memset(dis, 0x3f, sizeof dis); dis[1] = 0; q[ed++] = 1; while (bg < ed) { int u = q[bg++]; vis[u] = 0; for (int i = head[u]; ~i; i=ee[i].next) { int v = ee[i].to; if (ee[i].val > 0 && dis[v]>dis[u]+ee[i].cost) { dis[v]=dis[u]+ee[i].cost; fa[v] = u; pos[v] = i; if (!vis[v]) { vis[v] = 1; q[ed++] = v; } } } } if (dis[end] > k) return 0; return fa[end] != -1; } int minCost_maxFlow() { int flow = 0; int res = 0; while (spfa()) { int mn = 0x3fffffff; for (int i = end; i!= 1; i = fa[i]) { if (mn > ee[pos[i]].val) mn = ee[pos[i]].val; } for (int i = end; i!=1; i=fa[i]) { ee[pos[i]].val -= mn; ee[pos[i]^1].val += mn; } flow += mn; res += dis[end]; } return flow; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif while(scanf("%d%d%d", &n, &m, &k) && (n+m+k)) { end = n; cnt = 0; memset(head, -1, sizeof head); for (int i = 2; i< n; ++i) add(i, i+n, 0, 1); for (int i = 0; i< m; ++i) { int u, v; scanf("%d%d", &u, &v); if (u == 1) add(u, v, 1, 1); else add(u+n,v,1, 1); } printf("%d\n", minCost_maxFlow()); } return 0; }
hdu 1853 Cyclic Tour
若图中所有的点以圆环的形式存在,当且仅当每个点入度和出度均为1
#include<cstdio> #include<algorithm> #include<vector> #include<cmath> #include<set> #pragma comment(linker, "/STACK:1024000000,1024000000") // acm.hdu.edu.cn/showproblem.php?pid=1853 using namespace std; #define MAXN 205 int n, m; struct _node { int to, next, cost, val; _node(int a, int b, int c, int d): to(a),next(b),cost(c),val(d) {} _node() {} }ee[MAXN*MAXN]; int head[MAXN], cnt; int end ; void add(int u, int v, int cost, int val) { ee[cnt] = _node(v, head[u], cost, val); head[u] = cnt++; ee[cnt] = _node(u, head[v], -cost, 0); head[v] = cnt++; } int q[MAXN*MAXN], vis[MAXN], dis[MAXN], fa[MAXN]; int pos[MAXN]; int spfa() { int bg = 0, ed = 0; memset(vis, 0, sizeof vis); memset(fa, -1, sizeof fa); memset(dis, 0x3f, sizeof dis); dis[0] = 0; q[ed++] = 0; while (bg < ed) { int u = q[bg++]; vis[u] = 0; for (int i = head[u]; ~i; i=ee[i].next) { int v = ee[i].to; if (ee[i].val > 0 && dis[v]>dis[u]+ee[i].cost) { dis[v]=dis[u]+ee[i].cost; fa[v] = u; pos[v] = i; if (!vis[v]) { vis[v] = 1; q[ed++] = v; } } } } return fa[end] != -1; } int minCost_maxFlow() { int flow = 0; int res = 0; while (spfa()) { int mn = 0x3fffffff; for (int i = end; i!= 0; i = fa[i]) { if (mn > ee[pos[i]].val) mn = ee[pos[i]].val; } for (int i = end; i!=0; i=fa[i]) { ee[pos[i]].val -= mn; ee[pos[i]^1].val += mn; } flow += mn; res += dis[end]; } return flow!=n?-1:res; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif while(scanf("%d%d", &n, &m) !=EOF) { end = 2*n+1; cnt = 0; memset(head, -1, sizeof head); for (int i = 1; i<= n; ++i) add(0,i,0,1); for (int i = 0; i< m; ++i) { int u, v, c; scanf("%d%d%d", &u, &v, &c); add(u, v+n, c, 1); } for (int i = n+1; i< end; ++i) add(i, end, 0, 1); printf("%d\n", minCost_maxFlow()); } return 0; }
hdu 4494 Teamwork
各个种类间是不会互相影响的。对于有向图一般把一个点拆分成入和出两点,但题中由于工人可复用,所以再次引入一个点表示重复利用的工人。#include<cstdio> #include<algorithm> #include<vector> #include<cmath> #include<set> #pragma comment(linker, "/STACK:1024000000,1024000000") // acm.hdu.edu.cn/showproblem.php?pid=4494 using namespace std; const int MAXN = 155*3; int n, m; struct _node { int to, next, cost, val; _node(int a, int b, int c, int d): to(a),next(b),cost(c),val(d) {} _node() {} }ee[MAXN*200]; int head[MAXN], cnt; void add(int u, int v, int cost, int val) { ee[cnt] = _node(v, head[u], cost, val); head[u] = cnt++; ee[cnt] = _node(u, head[v], -cost, 0); head[v] = cnt++; } int q[MAXN*MAXN], vis[MAXN], dis[MAXN], fa[MAXN]; int pos[MAXN]; int db[MAXN], dc[MAXN], need[MAXN][5]; double dx[MAXN], dy[MAXN]; int spfa(int s, int t) { int bg = 0, ed = 0; memset(vis, 0, sizeof vis); memset(fa, -1, sizeof fa); memset(dis, 0x3f, sizeof dis); dis[s] = 0; q[ed++] = s; while (bg < ed) { int u = q[bg++]; vis[u] = 0; for (int i = head[u]; ~i; i=ee[i].next) { int v = ee[i].to; if (ee[i].val > 0 && dis[v]>dis[u]+ee[i].cost) { dis[v]=dis[u]+ee[i].cost; fa[v] = u; pos[v] = i; if (!vis[v]) { vis[v] = 1; q[ed++] = v; } } } } return fa[t] != -1; } int minCost_maxFlow() { int flow = 0; int res = 0; int end = 3*n+1, stt = 0; while (spfa(stt, end)) { int mn = 0x3fffffff; for (int i = end; i!= stt; i = fa[i]) { if (mn > ee[pos[i]].val) mn = ee[pos[i]].val; } for (int i = end; i!=stt; i=fa[i]) { ee[pos[i]].val -= mn; ee[pos[i]^1].val += mn; } flow += mn; res += dis[end]*mn; } return res; } void init() { cnt = 0; memset(head, -1, sizeof head); } double distce(double x, double y) { return sqrt(x*x + y*y); } double lenth[MAXN/3][MAXN/3]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int t; scanf("%d", &t); while(t--) { int res = 0; scanf("%d%d", &n, &m); scanf("%lf%lf", dx, dy); for (int i = 1; i< n; ++i) { scanf("%lf%lf%d%d", dx+i, dy+i, db+i, dc+i); for (int j = 0; j< m; ++j) scanf("%d", &need[i][j]); } for (int i = 1; i< n; ++i) for (int j = i+1; j< n; ++j) lenth[i][j] = lenth[j][i] = distce(dx[i]-dx[j], dy[i]-dy[j]); for (int i = 0; i< m; ++i) { init(); for (int j = 1; j<n; ++j) { add(0, j, 1, need[j][i]); add(j, j+n, 0, need[j][i]); add(j+n, 3*n+1, 0, need[j][i]); add(0, j+2*n, 0, need[j][i]); for (int k = 1; k< n; ++k) if (db[j]+dc[j]+lenth[j][k]<=db[k]) add(j+2*n, k+n, 0, need[j][i]); } res += minCost_maxFlow(); } printf("%d\n", res); } return 0; }
hdu 4067 Random Maze
能不能看出门道来建立数学模型才是这类问题的关键
hdu 3947 River Problem
很有意思的题目,感觉上有些像差分约束。关键是为了保证流入流出的平衡,选择用每条边减去其子节点的边#include<cstdio> #include<algorithm> #include<vector> #include<cmath> #include<set> #pragma comment(linker, "/STACK:1024000000,1024000000") //acm.hdu.edu.cn/showproblem.php?pid=3947 using namespace std; const int MAXN = 200, inf = 0x3f3f3f3f; int n, m; struct _node { int to, next, cost, val; _node(int a, int b, int c, int d): to(a),next(b),cost(c),val(d) {} _node() {} }ee[MAXN*MAXN]; int head[MAXN], cnt, ppre[MAXN], wt[MAXN]; void add(int u, int v, int cost, int val = inf) { ee[cnt] = _node(v, head[u], cost, val); head[u] = cnt++; ee[cnt] = _node(u, head[v], -cost, 0); head[v] = cnt++; } int q[MAXN*MAXN], vis[MAXN], dis[MAXN], fa[MAXN], pos[MAXN]; int spfa(int s, int t) { int bg = 0, ed = 0; memset(vis, 0, sizeof vis); memset(fa, -1, sizeof fa); memset(dis, 0x3f, sizeof dis); dis[s] = 0; q[ed++] = s; while (bg < ed) { int u = q[bg++]; vis[u] = 0; for (int i = head[u]; ~i; i=ee[i].next) { int v = ee[i].to; if (ee[i].val > 0 && dis[v]>dis[u]+ee[i].cost) { dis[v]=dis[u]+ee[i].cost; fa[v] = u; pos[v] = i; if (!vis[v]) { vis[v] = 1; q[ed++] = v; } } } } return fa[t] != -1; } int minCost_maxFlow(int s, int t, int all) { int flow = 0; int res = 0; while (spfa(s, t)) { int mn = inf; for (int i = t; i!= s; i = fa[i]) { if (mn > ee[pos[i]].val) mn = ee[pos[i]].val; } for (int i = t; i!=s; i=fa[i]) { ee[pos[i]].val -= mn; ee[pos[i]^1].val += mn; } flow += mn; res += dis[t]*mn; } if (flow != all) return -1; return res; } vector<int> sn[MAXN]; void minit() { cnt = 0; memset(head, -1, sizeof head); for (int i = 0; i < n+5; ++i) sn[i].clear(); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int T, cs = 0, s, t, all; scanf("%d", &T); while ( T--) { printf("Case #%d: ", ++cs); scanf("%d", &n); minit(); s = 0; t = n+2; all = 0; // add node 1 & n+1 for (int i = 1; i< n; ++i) { int u, v, w; scanf("%d%d%d", &u, &v, &w); wt[u] = w; ppre[u] = v; sn[v].push_back(u); } scanf("%d", &m); while (m--) { int u, v, l, c; scanf("%d%d%d%d", &u, &v, &l, &c); add(u, v, c, l); } for (int i = 1; i<= n; ++i) { int val = wt[i]; for (int j = 0, k=sn[i].size(); j<k; ++j) val -= wt[sn[i][j]], add(i, sn[i][j], 0); if (val >= 0) add(s, i, 0, val), all += val; else add(i, t, 0, -val); } printf("%d\n", minCost_maxFlow(s, t, all)); } return 0; }