HDU - 4888 最大流的方案是否为一

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4888
题目大意:题意:给一个n*m的矩形,往每个格子填0-k的数字,使得对第i行和为row[i],第i列和为col[i],问是否存在方案,方案是否唯一,如果方案唯一则输出具体方案。

在这里插入图片描述

建图:源点和每行连边,容量为每行的和。每列和汇点连边,容量为每列的和。每行和每列连边,容量为k。
判断是否存在唯一解,在残留网络里面能否找到一个环。

#include <bits/stdc++.h>
using namespace std;
const int maxm=400000;
const int maxn=1000;
const int inf=0x3f3f3f3f;

struct node{
    int u;
    int to;
    int flow;
    int next;
}e[maxm];

int start,tend,cut;
int head[maxn],work[maxn],dis[maxn],q[maxn];

inline void addcut(int u,int v,int c1)
{
    e[cut].u=u; e[cut].to=v,e[cut].flow=c1,e[cut].next=head[u],head[u]=cut++;
    e[cut].u=v; e[cut].to=u,e[cut].flow=0, e[cut].next=head[v],head[v]=cut++;
}
bool Dinic_bfs()
{
    int i,u,v,l,r=0;
    memset(dis, -1, sizeof(dis));
    dis[q[r++]=start]=0;
    for(l=0;l<r;++l)
        for(i=head[u=q[l]];i>=0;i=e[i].next)
            if(e[i].flow&&dis[v=e[i].to]<0)
            {
                dis[q[r++]=v]=dis[u]+1;
                if(v==tend)return 1;
            }
    return 0;
}
int Dinic_dfs(int u,int exp)
{
    if(u==tend)return exp;
    for(int &i=work[u],v,tmp;i>=0;i=e[i].next)
        if(e[i].flow&&dis[v=e[i].to]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,e[i].flow)))>0)
        {
            e[i].flow-=tmp;
            e[i^1].flow+=tmp;
            return tmp;
        }dis[u]--;
    return 0;
}
int Dinic_flow()
{
    int i,ret=0,delta;
    while(Dinic_bfs())
    {
        //改板子 保证访问到所有点
        /*************************/
        for(i=start;i<=tend;++i)work[i]=head[i];
        /**************************/
        while(delta=Dinic_dfs(start,inf))ret+=delta;
    }
    return ret;
}

int mp[500][500];
int mark[2000];
bool dfs(int u,int fa)
{
    if(mark[u]==true){
        return true;
    }
    int biu=-1;
    mark[u]=true;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa){
            biu=i;//这句话必须加,不加4975可以做 4888做不了
            continue;
        }
        if(e[i].flow>0){
            if(dfs(v,u)){
                return true;
            }
        }
        if(biu==-1){
            head[u]=e[i].next;
        }
        else{
            e[biu].next=e[i].next;
        }
        biu=i;
    }
    mark[u]=false;
    return false;
}

bool judge(int n)
{
    memset(mark,false,sizeof(mark));
    for(int i=0;i<=n;i++)
        if(dfs(i,-1))return true;
    return false;
}

int main()
{
    int n, m, k, T;
    while(scanf("%d%d%d", &n, &m, &k)!=EOF)
    {
        int x, sum1=0, sum2=0;
        cut=0;
        memset(head, -1, sizeof(head));
        for(int i=1; i<=n; i++){
            scanf("%d", &x);
            sum1+=x;
            addcut(0, i, x);
        }
        for(int i=1; i<=m; i++){
            scanf("%d", &x);
            sum2+=x;
            addcut(n+i, n+m+1, x);
        }
        for(int i=1; i<=n; i++){
            for(int j=1; j<=m; j++){
                addcut(i, n+j, k);
            }
        }
        start=0;tend=n+m+1;
        int max_s=Dinic_flow();
        if(max_s!=sum1||sum1!=sum2){
            printf("Impossible\n");
        }
        else{
            if(n==1||m==1||!judge(n+m+1)){
                for(int i=1; i<=cut; i+=2){
                    if(e[i].to<=n&&e[i].to>=1&&e[i].u-n<=m&&e[i].u-n>=0)
                    mp[e[i].to][e[i].u-n]=e[i].flow;
                }
                printf("Unique\n");
                for(int i=1; i<=n; i++){
                    for(int j=1; j<=m; j++){
                        printf("%d%c", mp[i][j], j==m?'\n':' ');
                    }
                }
            }
            else{
                printf("Not Unique\n");
            }
        }
    }
    return 0;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值