HDU 2426 Interesting Housing Problem 最小费用最大流 or KM算法
来源:互联网 发布:淘宝刷运费险 编辑:程序博客网 时间:2024/05/21 10:47
这道题貌似是08年杭州网络赛的题目, 看完题后就发现是个最优匹配问题,用KM或者最小费用最大流做, 就找了个最小费用最大流的模板,改了一下,就能过了、
建图还是比较好想的,建立一个超级源点,一个超级汇点,然后源点与学生连边,流量限制为1,费用为0,汇点与房间连边,流量限制为1, 费用为0, 然后学生与房间之间的边,流量限制是1,费用就是题目给的喜好值了, 注意,每次加边,都要加一个相应的反向边, 就是流量为0, 费用为正向边的负数。
然后题目中要求不能把学生分到不喜欢的房间里,所以碰见喜好值是负数就不管了。 另外,由于是最小费用么,所以所有喜好值都是乘以-1后加进去的,这样求出的最小值,输出的时候再乘以-1就变成最大的了。
最后判断能不能所有学生都分配到房间里, 就判断流量的大小是否等于学生个数就行了
/*ID: sdj22251PROG: subsetLANG: C++*/#include <iostream>#include <vector>#include <list>#include <map>#include <set>#include <deque>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <cctype>#include <string>#include <cstring>#include <cmath>#include <ctime>#define MAXN 100005#define eps 1e-11#define L(x) x<<1#define R(x) x<<1|1using namespace std;int tot = 0, x, y;class mincost{private: const static int V = 2001; //注意点的个数, 应该为学生+房间+2, 所以至少要开到1002 const static int E = 2000001; const static int INF = -1u >> 1; struct Edge { int v, cap, cost; Edge *next; } pool[E], *g[V], *pp, *pree[V]; int T, S, dis[V], pre[V]; int n, m, flow, cirq[V]; void SPFA(); inline void addedge(int i, int j, int cap, int cost);public: bool initialize(int x, int y, int z); void mincost_maxflow();};void mincost::mincost_maxflow(){ while (true) { SPFA(); if (dis[T] == INF) break; int minn = INF; for (int i = T; i != S; i = pre[i]) minn = min(minn, pree[i]->cap); for (int i = T; i != S; i = pre[i]) { pree[i]->cap -= minn; pool[(pree[i] - pool)^0x1].cap += minn; flow += minn * pree[i]->cost; } tot += minn; //流量计算 } if(tot != x) flow = 1; printf("%d\n", -flow);}void mincost::SPFA(){ bool vst[V] = {false}; int tail = 0, u; fill(dis,dis + n,0x7fffffff); cirq[0] = S; vst[S] = 1; dis[S] = 0; for (int i = 0; i <= tail; i++) { int v = cirq[i % n]; for (Edge *i = g[v]; i != NULL; i = i->next) { if (!i->cap) continue; u = i->v; if (i->cost + dis[v] < dis[u]) { dis[u] = i->cost + dis[v]; pree[u] = i; pre[u] = v; if (!vst[u]) { tail++; cirq[tail % n] = u; vst[u] = true; } } } vst[v] = false; }}void mincost::addedge(int i, int j, int cap, int cost){ pp->cap = cap; pp->v = j; pp->cost = cost; pp->next = g[i]; g[i] = pp++;}bool mincost::initialize(int x, int y, int z){ memset(g, 0, sizeof (g)); pp = pool; n = x + y + 2; //n即为顶点的个数 学生数+房间数+一个源点+一个汇点 m = z; S = 0; T = x + y + 1; int v, u, f, c; for (int i = 0; i < m; i++) { scanf("%d %d %d", &v, &u, &c); v++; u++; if(c >= 0) { addedge(v, u + x, 1, -c); addedge(u + x, v, 0, c); } } for(int i = 1; i <= x; i++) { addedge(0, i, 1, 0); addedge(i, 0, 0, 0); } for(int i = 1; i <= y; i++) { addedge(x + i, T, 1, 0); addedge(T, x + i, 0, 0); } flow = 0; return true;}mincost g;int main(){ //freopen("d:/data.in","r",stdin); //freopen("d:/data.out","w",stdout); int z, cas = 0; while(scanf("%d%d%d", &x, &y, &z) != EOF) { g.initialize(x, y, z); printf("Case %d: ", ++cas); tot = 0; g.mincost_maxflow(); } return 0;}
接下来是KM算法的 最后判断是否完备匹配就行了
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <queue>#define MAXN 505#define MAXM 555555#define INF 1000000000using namespace std;int n, m, ny, nx;int w[MAXN][MAXN];int lx[MAXN], ly[MAXN];int linky[MAXN];int visx[MAXN], visy[MAXN];int slack[MAXN];bool find(int x){ visx[x] = 1; for(int y = 1; y <= ny; y++) { if(visy[y]) continue; int t = lx[x] + ly[y] - w[x][y]; if(t == 0) { visy[y] = 1; if(linky[y] == -1 || find(linky[y])) { linky[y] = x; return true; } } else if(slack[y] > t) slack[y] = t; } return false;}void KM(){ memset(linky, -1, sizeof(linky)); for(int i = 1; i <= nx; i++) lx[i] = -INF; memset(ly, 0, sizeof(ly)); for(int i = 1; i <= nx; i++) for(int j = 1; j <= ny; j++) if(w[i][j] > lx[i]) lx[i] = w[i][j]; for(int x = 1; x <= nx; x++) { for(int i = 1; i <= ny; i++) slack[i] = INF; while(true) { memset(visx, 0, sizeof(visx));memset(visy, 0, sizeof(visy));if(find(x)) break;int d = INF;for(int i = 1; i <= ny; i++) if(!visy[i]) d = min(d, slack[i]); for(int i = 1; i <= nx; i++) if(visx[i]) lx[i] -=d; for(int i = 1; i <= ny; i++) if(visy[i]) ly[i] += d; else slack[i] -= d; } }}int main(){ int x, y, z, e, cas = 0; while(scanf("%d%d%d", &n, &m, &e) != EOF) { nx = n, ny = m; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) w[i][j] = -INF; while(e--) { scanf("%d%d%d", &x, &y, &z); if(z >= 0) w[x + 1][y + 1] = z; } printf("Case %d: ", ++cas); KM(); int cnt = 0, ans = 0; for(int i = 1; i <= ny; i++) if(linky[i] != -1 && w[linky[i]][i] != -INF) ans += w[linky[i]][i], cnt++; if(cnt != nx) ans = -1; printf("%d\n", ans); } return 0;}
- HDU 2426 Interesting Housing Problem 最小费用最大流 or KM算法
- HDU 2426 Interesting Housing Problem 二分匹配(KM模板)或者最小费用最大流
- hdoj 2246 Interesting Housing Problem 【最大费用最大流 or KM算法】
- hdu 2426 Interesting Housing Problem (KM算法)
- hdu 2426 Interesting Housing Problem 最大权值 && KM算法
- hdu 2426 Interesting Housing Problem (KM)
- hdu 2426 Interesting Housing Problem(KM)
- hdu 2426 Interesting Housing Problem【KM】
- POJ 2426 Interesting Housing Problem (最大费用最大流)
- HDU 2426 Interesting Housing Problem【最大费用最大流 && 常规题】
- hdoj--2426--Interesting Housing Problem(最大费用流)
- HDU 2426 Interesting Housing Problem(KM完美匹配)
- Interesting Housing Problem----KM
- HDU 2426 Interesting Housing Problem
- HDU-2426 Interesting Housing Problem
- hdu 2426 Interesting Housing Problem
- HDU 2426 Interesting Housing Problem
- HDU 2426 Interesting Housing Problem
- vmware虚拟机安装linux系统鼠标校准
- 页面重绘与重排版的性能影响
- android 数据保存方式
- php从二维数组随机取出多个单元
- 在C++中enum这样用为什么不行呢?
- HDU 2426 Interesting Housing Problem 最小费用最大流 or KM算法
- 反射--> 构造方法Constructor类的反射
- linux下测试程序运行的时间
- 判断文本是ANSI还是Unicode
- 排序算法总结
- 正则表达式30分钟入门教程
- oracle表分区详解
- CreateStatic CreateView
- Linux TC流量控制HOWTO中文版