POJ 2175 Evacuation Plan 最小费用流 消负圈
来源:互联网 发布:阿里云域名绑定服务器 编辑:程序博客网 时间:2024/05/21 17:52
解题思路:最开始一看标准的最小费用流的思路。
求出最小费用,然后和原先的答案进行比较。
不过这铁定会超时的,所以就死心吧...
接着从题目入手,
Output的最后一句,Your plan need not be optimal itself, but must be valid and better than The City Council's one.
挺阴的...
题目不要求给出最优解,只要一个比先前方案更优的解法就好。
如果把之前的给的方案看成费用流的方案之一的话,
我们只用对那个方案进行一下优化就行。
如果当前流是最优方案时,
当且仅当在残留网络中没有负圈。(后悔边也算在图中)
不然按该负圈回退一次流量,得到的方案的费用一定比原先更优,
且权值等于原先方案的权值加上该负圈的权值。
这样就把原先网络流的问题转化为找负圈的问题,
SPFA即可,只不过在每个点多记录了一个前驱边,在回退流量的时候用。
不过中间有个小bug,在SPFA的过程中,
当访问次数大于一定值时( 这题设为m就足够了 ) 返回的那个点不一定在负圈上,
也有可能是负圈上的点能够遍历的点,
这时就由该点处理一次才能找到一个负圈上的点,
然后再进行回退流量。
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <stack>using namespace std;#define FOR(i,l,r) for(int i=(l);i<=(r);++i)#define REP(i,n) for(int i=0;i<(n);++i)#define DSC(i,r,l) for(int i=(r);i>=(l);--i)#define INF 1e9const int MAXN=210;const int MAXM=100010;struct{ int x,y,c;} a[110],b[110];struct node{ int to; int next; int cost; int flow;} edge[MAXM];int head[MAXN],ip;int que[MAXN*MAXN];int tempc[MAXN];int dis[MAXN];int pre[MAXN];int out[MAXN];int map[110][110];bool visit[MAXN],flag[MAXN];void add(int u,int v,int f,int c){ edge[ip].to=v; edge[ip].flow=f; edge[ip].cost=c; edge[ip].next=head[u]; head[u]=ip++;}int m;int spfa(int start,int numpoint){ FOR(i,1,numpoint) dis[i]=INF; memset(visit,0,sizeof(visit)); memset(pre,-1,sizeof(pre)); memset(out,0,sizeof(out)); dis[start]=0; visit[start]=1; int l=-1,r=-1,top,to,temp; int mod=numpoint; que[++r]=start; while(l!=r) { top=que[++l]; visit[top]=0; for(int p=head[top]; p!=-1; p=edge[p].next) { if(!edge[p].flow) continue; to=edge[p].to; temp=dis[top]+edge[p].cost; if(dis[to]>temp) { dis[to]=temp; pre[to]=p^1; if(!visit[to]) { if(++out[to]>m+1) return to; visit[to]=1; que[++r]=to; } } } } return -1;}bool solve(int n,int m){ memset(flag,0,sizeof(flag)); int start=0; FOR(i,1,m) add(start,i+n,1,0); int temp=spfa(start,n+m+1); if(temp!=-1) { while(!flag[temp])//最初找到的这个点不一定在负圈上,要另加处理 { flag[temp]=1; temp=edge[ pre[temp] ].to; } int x=temp; edge[ pre[x] ].flow++; //回退流量 edge[ pre[x]^1 ].flow--;//回退流量 x=edge[ pre[x] ].to; while(x!=temp) { edge[ pre[x] ].flow++; //回退流量 edge[ pre[x]^1 ].flow--;//回退流量 x=edge[ pre[x] ].to; } return 1; } return 0;}int main(){ int n,x; //freopen("in.txt","r",stdin); while(cin>>n>>m) { memset(head,-1,sizeof(head)); ip=0; memset(tempc,0,sizeof(tempc)); //记录某个避难所已经使用了多少容量 FOR(i,1,n) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c); FOR(i,1,m) scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].c); FOR(i,1,n) FOR(j,1,m) map[i][j]=abs(a[i].x-b[j].x)+abs(a[i].y-b[j].y)+1; FOR(i,1,n) FOR(j,1,m) { scanf("%d",&x); add(i,j+n,INF,map[i][j]); add(j+n,i,x ,-map[i][j]);//后悔边 tempc[j]+=x; } int end=n+m+1; FOR(i,1,m) { add(i+n,end,b[i].c-tempc[i],0); add(end,i+n,tempc[i],0);//后悔边 } if(!solve(n,m)) puts("OPTIMAL"); else { puts("SUBOPTIMAL"); int temp=1; FOR(i,1,n) { FOR(j,1,m) { if(j>1) putchar(' '); printf("%d",edge[temp].flow); temp+=2; } printf("\n"); } } } return 0;}
- POJ 2175 Evacuation Plan 最小费用流 消负圈
- 消圈法解最小费用流(poj 2175 Evacuation Plan)
- poj 2175 Evacuation Plan(最小费用流+消圈)
- POJ 2175 Evacuation Plan 最小费用流(找负圈)
- *POJ 2175 Evacuation Plan | 费用流
- poj 2175 Evacuation Plan(最小费用流 (消圈算法))
- POJ 2175 Evacuation Plan (费用流,负环,消圈法,SPFA)
- [费用流 消圈原理] POJ 2175 Evacuation Plan
- 【费用流消圈】POJ-2175 Evacuation Plan
- POJ 2175 Evacuation Plan 费用流消圈
- POJ 2175 Evacuation Plan(费用流消负环)
- POJ 2175 Evacuation Plan 费用流消圈算法
- POJ 2175 Evacuation Plan 费用流消圈
- POJ2175 Evacuation Plan 【 最小费用流+消圈定理】
- POJ-2175-Evacuation Plan
- POJ 2175 Evacuation Plan
- Evacuation Plan (poj 2175 SPFA费用流消圈)
- POJ 2175 Evacuation Plan 笔记
- openwrt disable serial console message when booting
- linux rsync配置文件参数详解
- OnInit和OnLoad
- 第2.3节 android目录中manifest的介绍
- Struts中<logic:present><logic:iterator>的使用
- POJ 2175 Evacuation Plan 最小费用流 消负圈
- JS 技巧小全
- 遍历文件夹读取文件夹中图片并分页显示图片
- CatchLog 关键字搜索(往service传值,service取值)
- 存储引擎基础知识]InnoDB与MyISAM的六大区别
- nyist 21 三个水杯(BFS)
- android平台下使用点九PNG技术
- android onActivityResult
- 将eclipse java程序打包成jar的总结(包括工程中没有引用外部jar包和有引用外部jar包两种情况)