【POJ2396】Budget(有源汇的上下界可行流)

题意:要求构建一个m*n的矩阵,给出每行,每列的和,和C个要求:表示某个坐标的数必须严格”>”或”=”或”<”某个值,0是通配符,表示一整行(列)。
建图:
源点->横排 (该横排的和)
横排->该横排的点 (按C个要求给权值,分上界下界)
该横排的点->竖排(按C个要求给权值,分上界下界)
竖排->汇点(该竖排的和)
这就成了有源汇的可行流问题(不会的自行百度)百度:有源汇的上下界可行流

我先前写的代码及其恶心,边都要求边加边建图,调到最后卡了两天都没调出问题来,WA了15次。悲剧啊(;´д`)ゞ

其实不用这么复杂,只需要开一个数组,读要求时处理它的上下界,最后再来建图,
然后就A了(我还是不知道为什么先前的恶心代码A不掉。。。如果有人闲得实在无聊,欢迎来看WA

AC代码:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAXE 50000
#define MAXV 4300
#define MAXN 205
#define MAXM 25
#define INF 0x7FFFFFFF
#define code(a,b) ((a-1)*M+b+N+M)
int n,S,T;
int d[MAXV],cntd[MAXV];
struct Edge
{
    int id,w;
    int next;
    Edge(){}
    Edge(int _id,int _w){id=_id;w=_w;next=0;}
}edge[MAXE];
int _new,head[MAXV];
int G[MAXN][MAXM][2];
void add_edge(int a,int b,int w)
{
    int p;
    for(p=head[a];p&&edge[p].id!=b;p=edge[p].next);
    if(p){edge[p].w+=w;}
    else
    {
        edge[_new]=Edge(b,w);
        edge[_new].next=head[a];
        head[a]=_new;
        _new++;
    }
    for(p=head[b];p&&edge[p].id!=a;p=edge[p].next);
    if(!p)
    {
        edge[_new]=Edge(a,0);
        edge[_new].next=head[b];
        head[b]=_new;
        _new++;
    }
}
int aug(int now,int augco)
{
    int augc=augco,mn=n-1;
    if(now==T)
        return augco;
    for(int p=head[now],temp;p;p=edge[p].next)
        if(edge[p].w>0)
        {
            if(d[edge[p].id]==d[now]-1)
            {
                temp=min(augc,edge[p].w);
                temp=aug(edge[p].id,temp);
                edge[p].w-=temp;
                int q;
                for(q=head[edge[p].id];q&&edge[q].id!=now;q=edge[q].next);
                edge[q].w+=temp;
                augc-=temp;
                if(d[S]>=n)return augco-augc;
                if(augc==0)break;
            }
            mn=min(mn,d[edge[p].id]);
        }
    if(augco==augc)
    {
        cntd[d[now]]--;
        if(cntd[d[now]]==0)
            d[S]=n;
        d[now]=mn+1;
        cntd[d[now]]++;
    }
    return augco-augc;
}
int sap()
{
    memset(cntd,0,sizeof cntd);
    memset(d,0,sizeof d);
    int flow=0;
    cntd[0]=n;
    while(d[S]<n)
        flow+=aug(S,INF);
    return flow;
}
bool check()
{
    for(int p=head[S];p;p=edge[p].next)
        if(edge[p].w>0)
            return 0;
    return 1;
}
int N,M;
int main()
{
    int test;
    scanf("%d",&test);
    while(test--)
    {
        _new=1;
        memset(head,0,sizeof head);
        memset(edge,0,sizeof edge);
        scanf("%d%d",&N,&M);
        int ss=N*M+N+M+1,tt=ss+1;
        S=tt+1,T=S+1;
        for(int i=1,x;i<=N;i++)
        {
            scanf("%d",&x);
            add_edge(ss,T,x);
            add_edge(S,i,x);
        }
        for(int i=1,x;i<=M;i++)
        {
            scanf("%d",&x);
            add_edge(i+N,T,x);
            add_edge(S,tt,x);
        }
        for(int i=1;i<=N;i++)
            for(int j=1;j<=M;j++)
            {
                G[i][j][0]=0;
                G[i][j][1]=INF;
            }
        int C,a,b,w;
        char op[3];
        scanf("%d",&C);
        bool flag=1;
        for(int i=1;i<=C;i++)
        {
            scanf("%d%d%s%d",&a,&b,op,&w);
            for(int aa=a==0?1:a;((a==0&&aa<=N)||(a&&aa==a))&&flag;aa++)
                for(int bb=b==0?1:b;((b==0&&bb<=M)||(b&&bb==b))&&flag;bb++)
                {
                    if(op[0]=='>')
                    {
                        if(G[aa][bb][0]>w)continue;
                        G[aa][bb][0]=w+1;
                        if(G[aa][bb][0]>G[aa][bb][1])
                        {flag=0;break;}
                    }
                    if(op[0]=='=')
                    {
                        if(G[aa][bb][0]>w||G[aa][bb][1]<w)
                        {flag=0;break;}
                        G[aa][bb][0]=G[aa][bb][1]=w;
                    }
                    if(op[0]=='<')
                    {
                        if(G[aa][bb][1]<w)continue;
                        G[aa][bb][1]=w-1;
                        if(G[aa][bb][1]<G[aa][bb][0])
                        {flag=0;break;}
                    }
                }
        }
        if(flag)
        {
            for(int i=1;i<=N;i++)
                for(int j=1;j<=M;j++)
                {
                    add_edge(i,T,G[i][j][0]);
                    add_edge(S,code(i,j),G[i][j][0]);
                    add_edge(i,code(i,j),G[i][j][1]-G[i][j][0]);
                    add_edge(code(i,j),T,G[i][j][0]);
                    add_edge(S,j+N,G[i][j][0]);
                    add_edge(code(i,j),j+N,G[i][j][1]-G[i][j][0]);
                }
            add_edge(tt,ss,INF);
            n=T;
            sap();
        }
        if(!flag||!check())
            printf("IMPOSSIBLE\n");
        else
            for(int i=1,p,q;i<=N;i++)
            {
                for(int j=1;j<M;j++)
                {
                    for(p=head[(i-1)*M+j+N+M];p&&edge[p].id!=i;p=edge[p].next);
                    for(q=head[(i-1)*M+j+N+M];q&&edge[q].id!=S;q=edge[q].next);
                    printf("%d ",edge[p].w+edge[q].w);
                }
                for(p=head[(i-1)*M+M+N+M];p&&edge``
p].id!=i;p=edge[p].next);
                for(q=head[(i-1)*M+M+N+M];q&&edge[q].id!=S;q=edge[q].next);
                printf("%d\n",edge[p].w+edge[q].w);
            }
        if(test>1)printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值