poj2175费用流消圈算法
题意:
     有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 100000000
using 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;
}
poj2175费用流消圈算法的更多相关文章
- POJ 2175:Evacuation Plan(费用流消圈算法)***
		http://poj.org/problem?id=2175 题意:有n个楼,m个防空洞,每个楼有一个坐标和一个人数B,每个防空洞有一个坐标和容纳量C,从楼到防空洞需要的时间是其曼哈顿距离+1,现在给 ... 
- POJ 2157 Evacuation Plan [最小费用最大流][消圈算法]
		---恢复内容开始--- 题意略. 这题在poj直接求最小费用会超时,但是题意也没说要求最优解. 根据线圈定理,如果一个跑完最费用流的残余网络中存在负权环,那么顺着这个负权环跑流量为1那么会得到更小的 ... 
- poj 2175 费用流消圈
		题意抽象出来就是给了一个费用流的残存网络,判断该方案是不是最优方案,如果不是,还要求给出一个更优方案. 在给定残存网络上检查是否存在负环即可判断是否最优. 沿负环增广一轮即可得到更优方案. 考虑到制作 ... 
- POJ 2175 spfa费用流消圈
		题意:给出n栋房子位置和每栋房子里面的人数,m个避难所位置和每个避难所可容纳人数.然后给出一个方案,判断该方案是否最优,如果不是求出一个更优的方案. 思路:很容易想到用最小费用流求出最优时间,在与原方 ... 
- 【图论】Floyd消圈算法
		毫无卵用的百度百科 Definition&Solution 对于一个给定的链表,如何判定它是否存在环以及环的长度问题,可以使用Floyd消圈算法求出. 从某种意义上来讲,带环的链表在本质上是一 ... 
- Evacuation Plan-POJ2175最小费用消圈算法
		Time Limit: 1000MS Memory Limit: 65536K Special Judge Description The City has a number of municipal ... 
- hdu3315-My Brute(费用流 or KM算法)
		题目:My Brute Seaco是一个漂亮的妹子,喜欢玩一款名叫My Brute的游戏.情人节快到了,starvae和xingxing都想邀请妹子过节,但是妹子只能陪一个啊,于是两个人决定打一架,用 ... 
- 最小费用流判负环消圈算法(poj2175)
		Evacuation Plan Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3384 Accepted: 888 ... 
- POJ 2175 Evacuation Plan 费用流 负圈定理
		题目给了一个满足最大流的残量网络,判断是否费用最小. 如果残量网络中存在费用负圈,那么不是最优,在这个圈上增广,增广1的流量就行了. 1.SPFA中某个点入队超过n次,说明存在负环,但是这个点不一定在 ... 
随机推荐
- POJ-3159(差分约束+Dijikstra算法+Vector优化+向前星优化+java快速输入输出)
			Candies POJ-3159 这里是图论的一个应用,也就是差分约束.通过差分约束变换出一个图,再使用Dijikstra算法的链表优化形式而不是vector形式(否则超时). #include< ... 
- Codeforces 682C Alyona and the Tree
			题目链接:http://codeforces.com/problemset/problem/682/C 分析:存图,用dfs跑一遍,详细见注释 1 #include<iostream> 2 ... 
- 如何用Flink把数据sink到kafka多个不同(成百上千)topic中
			需求与场景 上游某业务数据量特别大,进入到kafka一个topic中(当然了这个topic的partition数必然多,有人肯定疑问为什么非要把如此庞大的数据写入到1个topic里,历史留下的问题,现 ... 
- css实现鼠标滑过出现从中间向两边扩散的下划线
			这个效果一开始我是在华为商城页面上看到的,刚开始还以为挺复杂,实现的时候还有点没头绪.不过,还好有百度,借此记录一下我在导航条上应用的实现方法. 主要是借助了伪元素,代码如下: <div cla ... 
- c++ 11 是如何简化你的数据库访问接口的
			之前写过一篇文章专门分析了 c++ 模板编译过程中报的一个错误:<fatal error C1045: 编译器限制 : 链接规范嵌套太深 >,其中涉及到了 qtl -- 一个使用 c++ ... 
- get和post的区别主要有以下几方面
			1.url可见性: get,参数url可见: post,url参数不可见 2.数据传输上: get,通过拼接url进行传递参数: post,通过body体传输参数 3.缓存性: get请求是可以缓存的 ... 
- Qt 自定义 进度条  纯代码
			一 结果图示 二 代码 头文件 #ifndef CPROGRESS_H #define CPROGRESS_H #include <QWidget> #include <QPaint ... 
- upx 手动脱壳
			查壳 UPX 0.89.6 - 1.02 / 1.05 - 2.90 (Delphi) stub -> Markus & Laszlo upx这类压缩壳手动脱壳非常简单. 一.查找oep ... 
- Python3实现短信轰炸机
			短信轰炸机的基本原理:利用某些限制不严格的网站短信注册接口,用Python模拟请求,传入被炸人手机号码,实现轰炸 实现方式:利用requests模块.time模块.完成请求模拟 模块安装: 在终端窗口 ... 
- java例题_33 等腰输出杨辉三角
			1 /*33 [程序 33 杨辉三角] 2 题目:打印出杨辉三角形(要求打印出 10 行如下图) 3 程序分析: 4 1 5 1 1 6 1 2 1 7 1 3 3 1 8 1 4 6 4 1 9 1 ... 
