POJ 2369 Budget【有上下界的最大流】

题意: 给出一个 n*m的矩阵,知道了每一行元素的和(n个),每一列元素的和(m个)

         给出t个条件:

     a b c d

         表示 a b 和 数字 d 满足条件 c

分析: 此题的最大流有下界的限制,用上下界最大流求解时,需要先去掉下界,判断是否存在可行流

         将 1 到 n 行每行看作一个节点(1..n),将 1 到 m 列每列看作一个节点(n+1..n+m)

         建立源点 s=0,汇点 t=n+m+1

         在源点 s 和每一个行节点之间连一条上界是行数字的和下界为 0的边

         在每一个列节点和和汇点t之间连一条上界是列数字的和下界为 0的边

         如果 i 行 j 列的数字大于 x,就在 i 行节点和 j 列节点之间连一条上界为INF,下界为 x+1 的边

         如果 i 行 j 列的数字小于 x,就在 i 行节点和 j 列节点之间连一条上界为x-1, 下界为 0 的边

         如果等于,上下界都是x

        建图之后, i 行与 j 列的流量就是 i,j的值

        如果最大流等于所有行元素的和,就存在解,输出流量即可。

#include<stdio.h>
#include<string.h>
#define clr(x)memset(x,0,sizeof(x))
#define maxn 300
#define INF 0x1f1f1f1f
#define min(a,b)(a)<(b)?(a):(b)
int cap[maxn][maxn];
int clow[maxn][maxn];
int flow[maxn][maxn];
void max_flow(int s,int t,int n)
{
    int p[maxn],a[maxn],q[maxn];
    int u,v,front,rear;
    for(;;)
    {
        clr(a);
        a[s]=INF;
        front=rear=0;
        q[rear++]=s;
        while(front<rear)
        {
            u=q[front++];
            for(v=0;v<n;v++)
                if(!a[v]&&flow[u][v]<cap[u][v])
                {
                    p[v]=u;
                    q[rear++]=v;
                    a[v]=min(a[u],cap[u][v]-flow[u][v]);
                }
        }
        if(a[t]==0)
            break;
        for(u=t;u!=s;u=p[u])
        {
            flow[p[u]][u]+=a[t];
            flow[u][p[u]]-=a[t];
        }
    }
}
int limit_flow(int s,int t,int n)
{
    int i,j,sk,ks;
    if(s==t)
        return INF;
    cap[n][n+1]=cap[n+1][n]=cap[n][n]=cap[n+1][n+1]=0;
    for(i=0;i<n;i++)
    {
        cap[n][i]=cap[i][n]=cap[n+1][i]=cap[i][n+1]=0;
        for(j=0;j<n;j++)
        {
            cap[i][j]-=clow[i][j];
            cap[n][i]+=clow[j][i];
            cap[i][n+1]+=clow[i][j];
        }
    }
    sk=cap[s][t];
    ks=cap[t][s];
    cap[s][t]=cap[t][s]=INF;
    max_flow(n,n+1,n+2);
    for(i=0;i<n;i++)
        if(flow[n][i]<cap[n][i])
            return -1;
    flow[s][t]=flow[t][s]=0;
    cap[s][t]=sk;
    cap[t][s]=ks;
    max_flow(s,t,n);
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
        {
            cap[i][j]+=clow[i][j];
            flow[i][j]+=clow[i][j];
        }
    i=j=0;
    while(i<n)
        j+=flow[s][i++];
    return j;
}
int main()
{
    int sum1,sum2,s,i,j,t,T,tot,n,m;
    bool flag;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        clr(cap);
        clr(clow);
        clr(flow);
        s=0;
        t=n+m+1;
        sum1=sum2=0;
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                cap[i][j+n]=INF;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&cap[s][i]);
            sum1+=cap[s][i];
        }
        for(i=n+1;i<=n+m;i++)
        {
            scanf("%d",&cap[i][t]);
            sum2+=cap[i][t];
        }
        flag=true;
        scanf("%d",&tot);
        while(tot--)
        {
            int a,b,w;
            int f1,f2,t1,t2;
            char ch[2];
            scanf("%d%d%s%d",&a,&b,ch,&w);
            f1=t1=a;
            f2=t2=b;
            if(a==0){ f1=1; t1=n;  }
            if(b==0){ f2=1; t2=m;  }
            
            for(i=f1;i<=t1;i++)
                for(j=f2;j<=t2;j++)
                {

                    if(ch[0]=='='){
                        cap[i][j+n]=clow[i][j+n]=w;
                        if(cap[s][i]<w||cap[j+n][t]<w)
                            flag=false;
                    }
                    else if(ch[0]=='>'&&clow[i][j+n]<w+1)
                    {
                        clow[i][j+n]=w+1;
                        if(cap[s][i]<w+1||cap[j+n][t]<w+1)
                            flag=false;
                    }
                    else if(ch[0]=='<'&&cap[i][j+n]>w-1)
                        cap[i][j+n]=w-1;
                }
        }
        if(sum1==sum2&&flag)
        {
            clr(flow);
            int rflow=limit_flow(s,t,t+1);
            if(rflow!=-1&&rflow==sum1)
            {
                for(i=1;i<=n;i++)
                    for(j=1;j<=m;j++)
                        printf("%d%c",flow[i][j+n],j==m?'\n':' ');
            }
            else
                printf("IMPOSSIBLE\n");
        }
        else printf("IMPOSSIBLE\n");
    }
    return 0;
}

 

posted @ 2012-08-22 19:28  'wind  阅读(307)  评论(0编辑  收藏  举报