poj2175费用流消圈算法
来源:互联网 发布:矩阵灯视频素材 编辑:程序博客网 时间:2024/04/29 06:22
题意:
有n个建筑,每个建筑有ai个人,有m个避难所,每个避难所的容量是bi,ai到bi的费用是|x1-x2|+|y1-y2|+1,然后给你一个n*m的矩阵,表示当前方案,问当前避难方案是否是最优的,如果不是,输出一个比这个好的就行。
思路:
大体看一下题目,很容易想到费用流直接去弄,建图也比较简单,但是费用流超时,仔细看上面的最后一句,是找到一个比当前的好就行,不用最好,这样我们可以考虑费用流的消圈,我也是今天第一次听到这个东西,研究了将近两个小时,大体明白了,明白后再反过来想想确实很简单,学东西就这样,很正常,下面说下消圈算法,消圈可以用来判断费用流的当前状态是否是最优的,大体是这样,我们先建立残余网络,就是根据题目给的信息建出残余图,如果是初学建议不要向网上很多人那样直接建立部分有用边(初学很容易不懂),我们可以这样,把所有的残余网络都补上,我写下本题的建边过程方便理解(正反边分开建立):
ss -> i 流量0 费用0
//因为跑完之后前面肯定是流量都用没了
i -> ss 流量c ,费用0
//c是这个建筑有多少人,满流的正向0,反向满c
i -> j + n 流量INF-c 费用 w
//w是i,j的距离+1,c是建筑里人数,本来是INF,跑完后是INF-c
j+n -> i 流量c ,费用w
//如上
j+n -> tt 流量q,费用0,
//q是建筑的容量剩余,就是所有的-当前用了的,当前用的综合自己算出来
tt -> j+n 流量p,费用0
//p是当前这个避难所一共用了多少容量
有n个建筑,每个建筑有ai个人,有m个避难所,每个避难所的容量是bi,ai到bi的费用是|x1-x2|+|y1-y2|+1,然后给你一个n*m的矩阵,表示当前方案,问当前避难方案是否是最优的,如果不是,输出一个比这个好的就行。
思路:
大体看一下题目,很容易想到费用流直接去弄,建图也比较简单,但是费用流超时,仔细看上面的最后一句,是找到一个比当前的好就行,不用最好,这样我们可以考虑费用流的消圈,我也是今天第一次听到这个东西,研究了将近两个小时,大体明白了,明白后再反过来想想确实很简单,学东西就这样,很正常,下面说下消圈算法,消圈可以用来判断费用流的当前状态是否是最优的,大体是这样,我们先建立残余网络,就是根据题目给的信息建出残余图,如果是初学建议不要向网上很多人那样直接建立部分有用边(初学很容易不懂),我们可以这样,把所有的残余网络都补上,我写下本题的建边过程方便理解(正反边分开建立):
ss -> i 流量0 费用0
//因为跑完之后前面肯定是流量都用没了
i -> ss 流量c ,费用0
//c是这个建筑有多少人,满流的正向0,反向满c
i -> j + n 流量INF-c 费用 w
//w是i,j的距离+1,c是建筑里人数,本来是INF,跑完后是INF-c
j+n -> i 流量c ,费用w
//如上
j+n -> tt 流量q,费用0,
//q是建筑的容量剩余,就是所有的-当前用了的,当前用的综合自己算出来
tt -> j+n 流量p,费用0
//p是当前这个避难所一共用了多少容量
建图之后从重点开始跑最短路,如果没有发现负权值回路那么就是最优的,否则我们就随便找到一个负权值回路,然后把i->j的边的流量++,j->i的边的流量--,至于为什么这样我们可以这样想,首先建议现在纸上大体画一下,自己随便找一个负权值回路,然后看看特点,从终点开始跑,发现负权值回路说明正值<负值(花费),那么我们把负值的流量-1给正值得流量+1,是不是即达到了流量平衡有减少了花费呢?还有找负权值回路的时候和费用流是一样的,费用更小(最短路)同时有流量才能跑,如果还不懂就不停的画,画着画着就懂了,还有画的过程中记得去想费用流的反向费用是负的,最大流的反向流量就是正向流量的减少量,还有一点就是注意一下,找负环的时候,如果用的是Spfa的话,最后一个有可能不是环上的,这样我们就得先找到一个肯定是环上的点,这个好办,直接mark,从后往前一直找到mark过的就跳出来,当前这个肯定是环上的(不明白的话可以在纸上画几个6感觉下),具体看代码。
#include<queue>#include<stdio.h>#include<string.h>#define N_node 205#define N_edge 30000#define INF 100000000using namespace std;typedef struct{ int from ,to ,cost ,flow ,next;}STAR;typedef struct{ int a ,b ,c;}NODE;STAR E[N_edge];int list[N_node] ,tot;int C[N_node];//入队次数int mer[N_node];//记录路径int s_x[N_node] ,mark[N_node];int now[N_node][N_node];NODE A[N_node] ,B[N_node];void add(int a ,int b ,int c ,int d){ E[++tot].from = a; E[tot].to = b; E[tot].cost = c; E[tot].flow = d; E[tot].next = list[a]; list[a] = tot;}int abss(int x){ return x > 0 ? x : -x;}bool Spfa(int s ,int n){ for(int i = 0 ;i <= n ;i ++) s_x[i] = INF; memset(mark ,0 ,sizeof(mark)); memset(C ,0 ,sizeof(C)); queue<int>q; q.push(s); mark[s] = C[s] = 1 ,s_x[s] = 0; int xin ,tou; memset(mer ,255 ,sizeof(mer)); while(!q.empty()) { tou = q.front(); q.pop(); mark[tou] = 0; for(int k = list[tou] ;k ;k = E[k].next) { xin = E[k].to; if(s_x[xin] > s_x[tou] + E[k].cost && E[k].flow) { s_x[xin] = s_x[tou] + E[k].cost; mer[xin] = k; if(!mark[xin]) { mark[xin] = 1; q.push(xin); if(++C[xin] > n) return xin; } } } } return 0;}int main (){ int n ,m ,i ,j; int st[N_node]; while(~scanf("%d %d" ,&n ,&m)) { for(i = 1 ;i <= n ;i++) scanf("%d %d %d" ,&A[i].a ,&A[i].b ,&A[i].c); for(i = 1 ;i <= m ;i ++) scanf("%d %d %d" ,&B[i].a ,&B[i].b ,&B[i].c); memset(st ,0 ,sizeof(st)); for(i = 1 ;i <= n ;i ++) for(j = 1 ;j <= m ;j ++) { scanf("%d" ,&now[i][j]); st[j] += now[i][j]; } memset(list ,0 ,sizeof(list)); tot = 1; int ss = 0 ,tt = n + m + 1; for(i = 1 ;i <= n ;i ++) add(ss ,i ,0 ,0),add(i ,ss ,0 ,A[i].c); for(i = 1 ;i <= m ;i ++) add(i + n ,tt ,0 ,B[i].c - st[i]) ,add(tt ,i + n ,0 ,st[i]); for(i = 1 ;i <= n ;i ++) for(j = 1 ;j <= m ;j ++) { add(i ,j + n ,abss(A[i].a-B[j].a)+abss(A[i].b - B[j].b) + 1 ,INF - now[i][j]); add(j + n ,i ,-(abss(A[i].a-B[j].a)+abss(A[i].b - B[j].b) + 1) ,now[i][j]); } int x = Spfa(tt ,tt); if(!x) { printf("OPTIMAL\n"); continue; } printf("SUBOPTIMAL\n"); memset(mark ,0 ,sizeof(mark)); i = mer[x]; while(1)//找到一个肯定在环上的点 { x = E[i].to; if(mark[x]) break; mark[x] = 1; i = mer[E[i].from]; } memset(mark ,0 ,sizeof(mark)); for(i = mer[x] ;i + 1 ;i = mer[E[i].from]) { int a = E[i].from ,b = E[i].to; if(a >= 1 && a <= n && b >= n + 1 && b <= n + m) now[a][b-n] ++; if(a >= n + 1 && a <= n + m && b >= 1 && b <= n) now[b][a-n] --; if(mark[a] && mark[b]) break; mark[a] = mark[b] = 1; } for(i = 1 ;i <= n ;i ++) for(j = 1 ;j <= m ;j ++) if(j == m) printf("%d\n" ,now[i][j]); else printf("%d " ,now[i][j]); } return 0;}
1 0
- poj2175费用流消圈算法
- POJ2175-最小费用流消圈算法
- 最小费用流判负环消圈算法(poj2175)
- Evacuation Plan-POJ2175最小费用消圈算法
- Poj2175(费用流,负环消圈)
- POJ2175 费用流消负圈
- 挑战P240 poj2175 最小费用最大流(TLE)
- POJ2175 Evacuation Plan 【 最小费用流+消圈定理】
- poj2175 Evacuation Plan (mcmf消圈算法)
- poj2175 Evacuation Plan 消圈算法(小组赛G)
- POJ 2175 Evacuation Plan 费用流消圈算法
- 【费用流算法:ZKW】
- 【消圈】poj2175
- 最小费用流算法模板
- 最小费用最大流算法
- 最小费用最大流算法
- 最小费用最大流算法
- 最小费用最大流算法
- weblogic集群session保持的问题
- 清结算概念
- 多事的键盘
- HDU 3047 带权并查集
- ZJ 虚拟机扩磁盘
- poj2175费用流消圈算法
- 在MFC中,设置ComboBox控件中下拉列表的高度
- 自定义组合控件关于LayoutInflater.from(context).inflate(R.layout.view_title, this,true)的问题
- 第十四周项目一:小玩文件
- SAP ERP统驭科目
- HTML5动画软件工具编辑器 HTML5动画分类 工具推荐
- java 过滤敏感词和特殊字符 防止sql注入
- unity 动态创建摄像机
- 启动之OS_CPU_C