POJ2175.Evacuation Plan

【题意】

坐标系中,有n个建筑,给定坐标和建筑内人数和m个避难点,给定坐标和容量

定义每个人走的距离为|x1-x2|+|y1-y2|+1,问给定的方案是否是最优方案

【分析】

费用流消圈例题

我们按照给定方案建立残量网络,寻找负环进行增广即可

正常的消圈算法是不断找负环直到没有为止,但这道题目只要求找到一个更优的即可, 所以就直接找到一个环流1的流量即可

【代码】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=105;
const int maxm=1e5+5;
struct dot
{
    int x,y;
}a[maxn],b[maxn];
int c[maxn],d[maxn],ans[maxn][maxn];
int head[maxm],n,m,T,dis[maxn][maxn];
int pre[maxm],cnt[maxm],vis[maxm];
int dist[maxm],viss[maxm];
int tot,sum[maxm];
struct edge
{
    int to,nxt,v;
}e[maxm<<1];
void add(int x,int y,int z)
{
    e[++tot].to=y; e[tot].v=z; e[tot].nxt=head[x]; head[x]=tot;
}
int spfa(int s)
{
    queue <int> q; q.push(s);
    memset(viss,0,sizeof(viss));
    memset(dist,0x3f,sizeof(dist));
    cnt[s]++ ; viss[s]=1; dist[s]=0;
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        viss[u]=0;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int to=e[i].to;
            if(dist[to]>dist[u]+e[i].v)
            {
                dist[to]=dist[u]+e[i].v;
                pre[to]=u;
                if(!viss[to])
                {
                    viss[to]=1;
                    q.push(to);
                    if(++cnt[to]>=T)
                        return to;
                }
            }
        }
    }
    return -1;
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(head,0,sizeof(head));
        memset(cnt,0,sizeof(cnt));
        memset(vis,0,sizeof(vis));
        memset(pre,0,sizeof(pre));
        tot=1;
        T=m+n+1;
        for(int i=1;i<=n;i++)
            scanf("%d%d%d",&a[i].x,&a[i].y,&c[i]);
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&b[i].x,&b[i].y,&d[i]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                dis[i][j]=abs(a[i].x-b[j].x)+abs(a[i].y-b[j].y)+1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&ans[i][j]);
                if(ans[i][j])
                    add(j+n,i,-dis[i][j]);
                if(ans[i][j]!=c[i])
                    add(i,j+n,dis[i][j]);
                sum[j]+=ans[i][j];
            }
        for(int i=1;i<=m;i++)
        {
            if(sum[i]>0)
                add(T,i+n,0);
            if(sum[i]<d[i])
                add(i+n,T,0);
        }
        int id=spfa(T);
        if(id==-1)
        {
            printf("OPTIMAL\n");
            continue;
        }
        printf("SUBOPTIMAL\n");
        while(!vis[id])
        {
            vis[id]=1;
            id=pre[id];
        }
        int st=id;
        do
        {
            int u=pre[st];
            int v=st;
            if(u<=n && v>n)
                ans[u][v-n]++;
            if(v<=n && u>n)
                ans[v][u-n]--;
            st=pre[st];
        }while(st!=id);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                printf("%d ",ans[i][j]);
            printf("\n");
        }
    }
    return 0;
}

 

posted @ 2021-06-07 15:02  andyc_03  阅读(62)  评论(0编辑  收藏  举报