博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ 2175 Evacuation Plan
阅读量:5076 次
发布时间:2019-06-12

本文共 2726 字,大约阅读时间需要 9 分钟。

POJ_2175

    据说这个题目裸着做费用流会超时,不过实际上看完这个题目还是不难发现更好的思路的,因为题目又没要求要最优解,而是得到一个更优的解,那么如果在原图中能够找到一个总费用为负的回路的话,那么沿这个回路流量增加1就能够在不改变原始总流量的基础上使总费用变得更低,于是我们只要试图去找这样一个负圈就可以了。

    如果用的SPFA的话,在一个点入队次数大于顶点数时就可以判断有负圈存在了,但这时刚刚入队的这个点却未必是负圈上的,但我们可以记录下来每个点被更新的前一个点,沿这个路径不停地回溯去找,直到发现找到的这个点在之间已经遇到过了,那么找到的这个点就一定是某个负圈上的点了。最后以这个点为基础,回溯找到整个负圈并更新流量即可。

    如果用Bellman-Ford的话,找负圈上的点就要更加纠结一些了……

#include
#include
#include
#define MAXD 210#define MAXM 20410#define INF 0x3f3f3f3fint N, M, first[MAXD], e, next[MAXM], v[MAXM], flow[MAXM], cost[MAXM];int dis[MAXD], pre[MAXD], vis[MAXD], sum[MAXD];struct Point{ int x, y, z;}p[MAXD];int Dis(int i, int j){ return abs(p[i].x - p[j].x) + abs(p[i].y - p[j].y) + 1;}void add(int x, int y, int f, int c){ v[e] = y, flow[e] = f, cost[e] = c; next[e] = first[x], first[x] = e ++; }void init(){ int i, j, x, y, z; memset(first, -1, sizeof(first[0]) * (N + M + 1)), e = 0; for(i = 0; i < N + M; i ++) scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z); memset(sum, 0, sizeof(sum[0]) * M); for(i = 0; i < N; i ++) for(j = 0; j < M; j ++) { scanf("%d", &x), sum[j] += x; add(i, N + j, INF - x, Dis(i, N + j)), add(N + j, i, x, -Dis(i, N + j)); } for(i = 0; i < M; i ++) add(N + i, N + M, p[N + i].z - sum[i], 0), add(N + M, N + i, sum[i], 0);}int dfs(int cur, int &x){ int i = pre[cur]; if(i == -1 || vis[cur] == 1) return 0; if(vis[cur] == -1) { x = cur; return 1; } vis[cur] = -1; if(dfs(v[i ^ 1], x)) return 1; vis[cur] = 1; return 0;}void print(){ int i, j, x; memset(vis, 0, sizeof(vis[0]) * (N + M + 1)); for(i = 0; i <= N + M; i ++) if(!vis[i] && dfs(i, x)) break; for(i = pre[x]; ; i = pre[v[i ^ 1]]) { flow[i] -= 1, flow[i ^ 1] += 1; if(v[i ^ 1] == x) break; } printf("SUBOPTIMAL\n"); for(i = 0; i < N; i ++) { printf("%d", flow[i * M * 2 + 1]); for(j = 1; j < M; j ++) printf(" %d", flow[(i * M + j) * 2 + 1]); printf("\n"); }}void solve(){ int i, j, flag; memset(dis, 0, sizeof(dis[0]) * (N + M + 1)); memset(pre, -1, sizeof(pre[0]) * (N + M + 1)); for(i = 0; i <= N + M; i ++) { flag = 0; for(j = 0; j < e; j ++) if(flow[j] && dis[v[j]] > dis[v[j ^ 1]] + cost[j]) dis[v[j]] = dis[v[j ^ 1]] + cost[j], pre[v[j]] = j, flag = 1; if(flag == 0) break; } if(i > N + M) print(); else printf("OPTIMAL\n");}int main(){ while(scanf("%d%d", &N, &M) == 2) { init(); solve(); } return 0; }

转载于:https://www.cnblogs.com/staginner/archive/2012/08/20/2647946.html

你可能感兴趣的文章
JavaScript 克隆数组
查看>>
eggs
查看>>
一步步学习微软InfoPath2010和SP2010--第七章节--从SP列表和业务数据连接接收数据(4)--外部项目选取器和业务数据连接...
查看>>
oracle 报错ORA-12514: TNS:listener does not currently know of service requested in connec
查看>>
基于grunt构建的前端集成开发环境
查看>>
利用循环播放dataurl的视频来防止锁屏:NoSleep.js
查看>>
python3 生成器与迭代器
查看>>
java编写提升性能的代码
查看>>
Abstract Factory Pattern
查看>>
list 容器 排序函数.xml
查看>>
《Genesis-3D开源游戏引擎完整实例教程-跑酷游戏篇03:暂停游戏》
查看>>
CPU,寄存器,一缓二缓.... RAM ROM 外部存储器等简介
查看>>
windows下编译FreeSwitch
查看>>
git .gitignore 文件不起作用
查看>>
Alan Turing的纪录片观后感
查看>>
c#自定义控件中的事件处理
查看>>
django Models 常用的字段和参数
查看>>
IOS--沙盒机制
查看>>
使用 JointCode.Shuttle 访问任意 AppDomain 的服务
查看>>
sqlite的坑
查看>>