POJ.2175.Evacuation Plan(消圈)

POJ


\(Description\)

\(n\)个建筑物,每个建筑物里有\(a_i\)个人;\(m\)个避难所,每个避难所可以容纳\(b_i\)个人。
给出每个建筑物及避难所的坐标,任意两点间的距离为它们的曼哈顿距离\(+1\)。
现在给出一个分配方案(\(g[i][j]\)表示第\(i\)个建筑物去第\(j\)个避难所的人数),问是否存在所有人移动的距离之和比当前更小的方案。如果存在,输出任意一组更小的方案。
\(n,m\leq100\)

\(Solution\)

直接跑费用流会T,但是也没必要。
如果残量网络存在负环(只走有流量的边),那么沿该负环继续增广,可以得到一组更优的解。否则就是当前流量下的最小费用流。
所以建出残量网络,找出负环来,在负环上走一遍就行了。
\(S\to i\)的每条边的流量肯定是流满的,所以不需要建(\(i'\to T\)的就不一定了)。
复杂度\(O(nm)\)。


//688K  329MS
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=205,M=(105*105+N)*2,INF=0x3f3f3f3f;

int Enum,H[N],nxt[M],to[M],cost[M],dis[N],pre[N],g[105][105];

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now*f;
}
inline void AE(int u,int v,int w,int c)
{
    if(w) to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum, cost[Enum]=c;
}
int SPFA(const int n)
{
    static int tm[N];
    static bool inq[N];
    std::queue<int> q;
    memset(dis,0x3f,n+1<<2);
    dis[n]=0, q.push(n), tm[n]=1;
    while(!q.empty())
    {
        int x=q.front(); q.pop();
        inq[x]=0;
        for(int i=H[x],v; i; i=nxt[i])
            if(dis[to[i]]>dis[x]+cost[i])
            {
                dis[v=to[i]]=dis[x]+cost[i], pre[v]=x;
                if(!inq[v])
                {
                    if(++tm[v]>=n) return v;
                    q.push(v), inq[v]=1;
                }
            }
    }
    return -1;
}
void FindCircle(int x,const int n)
{
    static bool vis[N];
    while(!vis[x]) vis[x]=1, x=pre[x];//p不一定在环上(但是能回到环),应该先找出来啊。。
    int tmp=x;
    do
    {
        int v=pre[x];//v->x
        if(x<=n && v>n) --g[x][v-n];
        else if(x>n && v<=n) ++g[v][x-n];
        x=v;
    }while(x!=tmp);
}

int main()
{
    static int a[N],b[N],c[N],d[N],cap[N],use[N];
    const int n=read(),m=read(),T=n+m+1;
    for(int i=1; i<=n; ++i) a[i]=read(),b[i]=read(),read();
    for(int i=1; i<=m; ++i) c[i]=read(),d[i]=read(),cap[i]=read();
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=m; ++j)
        {
            use[j]+=g[i][j]=read();
            int cost=std::abs(a[i]-c[j])+std::abs(b[i]-d[j])+1;
            AE(i,j+n,INF-g[i][j],cost), AE(j+n,i,g[i][j],-cost);//negative!
        }
    for(int i=1; i<=m; ++i) AE(i+n,T,cap[i]-use[i],0), AE(T,i+n,use[i],0);
    int p=SPFA(T);
    if(p==-1) puts("OPTIMAL");
    else
    {
        FindCircle(p,n), puts("SUBOPTIMAL");
        for(int i=1; i<=n; ++i,putchar('\n'))
            for(int j=1; j<=m; ++j) printf("%d ",g[i][j]);
    }

    return 0;
}

原文地址:https://www.cnblogs.com/SovietPower/p/10343008.html

时间: 2024-10-11 23:15:15

POJ.2175.Evacuation Plan(消圈)的相关文章

POJ 2175 Evacuation Plan 费用流 负圈定理

题目给了一个满足最大流的残量网络,判断是否费用最小. 如果残量网络中存在费用负圈,那么不是最优,在这个圈上增广,增广1的流量就行了. 1.SPFA中某个点入队超过n次,说明存在负环,但是这个点不一定在负环上. 2.这个负环可能包括汇点t,所以构建残量网络的时候也要考虑防空洞到t上的容量. //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring

POJ 2175 Evacuation Plan (费用流,负环,消圈法,SPFA)

http://poj.org/problem?id=2175 Evacuation Plan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3256   Accepted: 855   Special Judge Description The City has a number of municipal buildings and a number of fallout shelters that were build

POJ 2175 Evacuation Plan 费用流消圈

题目大意:给出一个费用流的模型和已经流过的一些边,问是否存在比这个解更优的解. 思路:直接用原图做一次费用流求最优解会T掉.先介绍费用流消圈定理:如果当前费用流的残量网络中存在负圈,那么当前流不是最优的解. 其实很好理解,结合原图和流过流量之后的反边,若出现了负圈,那么就可以沿着这个负圈增广,而且费用更小. 不过为了解决这个题我们并不需要建立完整的网络流,只需要建立残量网络之后SPFA看是否能找到负环即可. 具体建立方法: 如果一个避难地点有值,那么T向这个避难地点连边,费用0 若当前避难地点没

POJ 2175 Evacuation Plan

Evacuation Plan Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 217564-bit integer IO format: %lld      Java class name: Main The City has a number of municipal buildings and a number of fallout shelters that

POJ - 2175 Evacuation Plan (最小费用流消圈)

题意:有N栋楼,每栋楼有\(val_i\)个人要避难,现在有M个避难所,每个避难所的容量为\(cap_i\),每个人从楼i到避难所j的话费是两者的曼哈顿距离.现在给出解决方案,问这个解决方案是否是花费最小的,若不是,则给出比这个更优的解. 分析:若只是要我们求一个最优解的话就用费用流做.现在要求判断是否最优,那么就是当前这张图中是否最短路还能被更新. 首先需要根据给定的解决方案重现这个状态下的残余网,其实只需要加入必要的弧即可:对与任意的楼与避难所(i,j),建边,费用为其距离;若i->j有流量

POJ 2135.Farm Tour 消负圈法最小费用流

Evacuation Plan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4914   Accepted: 1284   Special Judge Description The City has a number of municipal buildings and a number of fallout shelters that were build specially to hide municipal w

ZOJ 1553 Evacuation Plan

最小费用最大流..... 建图: 源点 到 每栋楼  连容量为B,花费为0 的边 每个避难所 到 汇点  连容量为C,花费为0 的边 楼 到 避难所 连容量INF,花费 曼哈顿距离+1 的边 跑费用流后比较.... POJ 2175时限只有一秒.....会超时 Evacuation Plan Time Limit: 10000MS   Memory Limit: 32768KB   64bit IO Format: %lld & %llu [Submit]   [Go Back]   [Stat

解题报告 之 POJ2175 Evacuation Plan

解题报告 之 POJ2175 Evacuation Plan Description The City has a number of municipal buildings and a number of fallout shelters that were build specially to hide municipal workers in case of a nuclear war. Each fallout shelter has a limited capacity in term

POJ 2065 SETI (高斯消元 取模)

题目链接 题意: 输入一个素数p和一个字符串s(只包含小写字母和‘*’),字符串中每个字符对应一个数字,'*'对应0,‘a’对应1,‘b’对应2.... 例如str[] = "abc", 那么说明 n=3, 字符串所对应的数列为1, 2, 3. 题目中定义了一个函数: a0*1^0 + a1*1^1+a2*1^2+........+an-1*1^(n-1) = f(1)(mod p), f(1) = str[0] = a = 1; a0*2^0 + a1*2^1+a2*2^2+....