POJ2175 费用流消负圈

题意: n个房子,m个避难所,接下来n行,房子的坐标和人数,m行,避难所的坐标和容量,接下来n*m矩阵表示当前方案,房子 I 去避难所 j 的人数,问有没有更优方案。


思路:一开始直接用费用流,TLE了,后来想了很久不知道怎么做,看别人的博客,明白是个消圈问题,即判断从汇点到源点有无负圈,如果有则存在更优方案。现在还没完全理解,以后再补充。


链接:http://poj.org/problem?id=2175


代码:

#include<cstdio>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<string.h>
#include<map>
#define eps 1e-9
#define nn 205
#define INF 0x7FFFFFFF
#define inf 0x7F7F7F7F
#define pi acos(-1)
#define mod 1000000007
#define LL long long

using namespace std;

/*-----------------------------never more!---------------------------*/

/*
 _______________#########_______________________
______________############_____________________
______________#############____________________
_____________##__###########___________________
____________###__######_#####__________________
____________###_#######___####_________________
___________###__##########_####________________
__________####__###########_####_______________
________#####___###########__#####_____________
_______######___###_########___#####___________
_______#####___###___########___######_________
______######___###__###########___######_______
_____######___####_##############__######______
____#######__#####################_#######_____
____#######__##############################____
___#######__######_#################_#######___
___#######__######_######_#########___######___
___#######____##__######___######_____######___
___#######________######____#####_____#####____
____######________#####_____#####_____####_____
_____#####________####______#####_____###______
______#####______;###________###______#________
________##_______####________####______________
                                      葱官赐福  百无禁忌

 */

struct node
{
    int st;
    int en;
    int flow,cost;
    int next;
}E[nn*nn];
int num;
int p[nn];
void init()
{
    memset(p,-1,sizeof p);
    num=0;
}
void add(int st,int en,int flow,int cost)
{
    //printf("xxxxxx:%d %d %d %d\n",st,en,flow,cost);
    E[num].st=st;
    E[num].en=en;
    E[num].flow=flow;
    E[num].cost=cost;
    E[num].next=p[st];
    p[st]=num++;
    /*E[num].st=en;
    E[num].en=st;
    E[num].flow=0;
    E[num].cost=-cost;
    E[num].next=p[en];
    p[en]=num++;*/
}

int EE[nn][nn],ANS[nn][nn],du[nn],sum[nn];
int n,m,g[nn][nn];

int pre[nn];
int dis[nn];
bool fg[nn];

int spfa(int st,int en)
{
    for(int i=0;i<=en;i++)
        fg[i]=0,dis[i]=inf,pre[i]=-1,du[i]=0;
    queue<int>q;
    q.push(en);
    fg[en]=1;
    dis[en]=0;
    du[en]++;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        fg[u]=0;
        for(int i=p[u];i+1;i=E[i].next)
        {
            int v=E[i].en;
            if(E[i].flow&&dis[v]>dis[u]+E[i].cost)
            {
                dis[v]=dis[u]+E[i].cost;
                pre[v]=u;
                if(!fg[v])
                {
                    fg[v]=1;
                    du[v]++;
                    q.push(v);
                    if(du[v]>n+m+2)
                        return v;
                }
            }
        }
    }
    return -1;
}


void solve(int st,int en)
{
    int rt=spfa(st,en);
    if(rt!=-1)
    {
        puts("SUBOPTIMAL");
        memset(fg,0,sizeof(fg));
        int sta=rt;
        while(1)
        {
            //printf("%d\n",sta);
            if(!fg[sta])
            {
                fg[sta]=1;
                sta=pre[sta];
            }
            else
            {
                rt=sta;
                break;
            }
        }
        do
        {
            int from=pre[sta],to=sta;
            if(from<=n&&to>n)
                g[from][to-n]++;
            if(to<=n&&from>n)
                g[to][from-n]--;
            sta=pre[sta];
        }while(sta!=rt);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                printf("%d%c",g[i][j],j==m?'\n':' ');
    }
    else
        puts("OPTIMAL");
}

struct people
{
    int x,y,c;
}a[nn],b[nn];

int dit(people a,people b)
{
    return abs(a.x-b.x)+abs(a.y-b.y)+1;
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int i,j;
        init();
        int S=0,T=n+m+1;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);
        }
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].c);
            sum[i]=0;
        }
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                EE[i][j]=dit(a[i],b[j]);
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                scanf("%d",&g[i][j]);
                sum[j]+=g[i][j];
            }
        }

        /*for(i=1;i<=n;i++)
            printf("%d ",sum[0][i]);
        printf("\n");
        for(i=1;i<=m;i++)
            printf("%d ",sum[1][i]);
        printf("\n");*/

        for(i=1;i<=n;i++)
        {
            add(S,i,0,0);
            add(i,S,a[i].c,0);
            for(j=1;j<=m;j++)
            {
                add(i,j+n,INF-g[i][j],EE[i][j]);
                add(j+n,i,g[i][j],-EE[i][j]);
            }
        }
        for(j=1;j<=m;j++)
        {
            //printf("sum:%d\n",sum[j]);
            add(j+n,T,b[j].c-sum[j],0);
            add(T,j+n,sum[j],0);
        }
        solve(S,T);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值