hdu4888 Redraw Beautiful Drawings 最大流

最大流的一种类型的题,把每一行,每一列做一个点,连接源点到行,列到汇点,行到列。跑一遍最大流。

如何判断unique?  按行dp,  dp[i][j] 表示在当前行,i未满且j不空,(若存在某两行的   dp[i][j]&&dp[j][i] == 1 , 那么结果不唯一 !!!)。

另一种方法:在残留网络中找环,若存在,则答案不唯一。

看代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#include<cstdlib>
#include<queue>
using namespace std;
const int nMax = 1e3+10;
const int INF = 99999999;
struct Edge{
    int v,flow,nxt;
}edge[nMax*nMax];
int g[nMax],nume;
int src,sink;
int n,m,k;
int Map[nMax][nMax];
inline int addedge(int u,int v,int flow)
{
    edge[++nume].v = v,edge[nume].flow = flow,edge[nume].nxt = g[u],g[u] = nume;
    edge[++nume].v = u,edge[nume].flow = 0   ,edge[nume].nxt = g[v],g[v] = nume;
    return nume;
}
void init()
{
    memset(g,0,sizeof(g));
    nume = 1;
}
int tot_x,tot_y;
void build()
{
    init();
    tot_x = tot_y = 0;
    src = 0,sink = n+m+1;
    for(int i = 1;i <= n;i++){
        int x;
        scanf("%d",&x);
        tot_x += x;
        addedge(src,i,x);
    }
    for(int i = 1;i <= m;i++){
        int x;
        scanf("%d",&x);
        tot_y += x;
        addedge(i+n,sink,x);
    }
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++){
            Map[i][j] = addedge(i,j+n,k);
        }
}
int que[nMax],dist[nMax];
bool dinic_bfs()
{
    memset(dist,63,sizeof(dist));
    int hc=dist[0];
    dist[src] = 0;
    que[0] = src;
    for(int l = 0,r = 0;l <= r;l++){
        int cur = que[l];
        for(int i = g[cur]; i ;i = edge[i].nxt){
            int v = edge[i].v;
            if( edge[i].flow && dist[v]==hc ){
                dist[v] = dist[cur] + 1;
                if( v == sink )
                    return true;
                que[++r] = v;
            }
        }
    }
    return false;
}
int c[nMax],p[nMax],st[nMax];
int dinic_dfs()
{
    int ret = 0,top = 0;
    memcpy(c,g,sizeof(g));
    st[++top] = src;
    while( top ){
        int cur = st[top];
        if( cur != sink ){
            int i;
            for(i = c[cur]; i ;i = edge[i].nxt)
                if( edge[i].flow && dist[edge[i].v] == dist[cur] + 1 )
                    break;
            if( i )
                st[++top] = edge[i].v,c[cur] = p[top] = i;
            else
                --top,dist[cur] = INF;
        }
        else{
            int delta = INF;
            for(int i = top;i >= 2;i--)
                delta = min(delta,edge[p[i]].flow);
            for(int i = top;i >= 2;i--){
                edge[p[i]].flow -= delta;
                edge[p[i]^1].flow += delta;
                if( !edge[p[i]].flow )
                    top = i-1;
            }
            ret += delta;
        }
    }
    return ret;
}
int dinic()
{
    int ret = 0;
    while( dinic_bfs() ){
        ret += dinic_dfs();
    }
    return ret;
}
int dp[nMax][nMax];
int is()
{
    memset(dp,0,sizeof(dp));
    int v1,v2;
    for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                for(int kk=j+1;kk<=m;kk++){
                    v1=v2=0;
                    if(edge[Map[i][j]].flow<k && edge[Map[i][kk]].flow>0)
                        if(dp[kk][j]==1) {return 1;}
                        else v1=1;
                    if(edge[Map[i][kk]].flow<k && edge[Map[i][j]].flow>0)
                        if(dp[j][kk]==1) {return 1;}
                        else v2=1;
                    if(v1) dp[j][kk]=1;
                    if(v2) dp[kk][j]=1;
                }
        }
    return 0;
}
int vis[nMax];
int main()
{
    while( scanf("%d %d %d",&n,&m,&k) != EOF ){
        build();
        int temp = dinic();
        int flag = 0;
        if( tot_x != tot_y || tot_x != temp )
            puts("Impossible");
        else if( flag=is() )
            puts("Not Unique");
        else{
            puts("Unique");
            for(int i = 1;i <= n;i++){
                for(int j = 1;j < m;j++)
                    printf("%d ",edge[Map[i][j]].flow);
                printf("%d\n",edge[Map[i][m]].flow);
            }
        }
    }
    return 0;
}
方法二:

bool dfs(int cur,int fa,int _final)
{
    vis[cur] = 1;
    for(int i = g[cur]; i ;i = edge[i].nxt){
        int v = edge[i].v;
        if( v == fa )
            continue;
        if( v == _final && edge[i].flow )
            return true;
        else if( !vis[v] && edge[i].flow ){
            if( dfs(v,cur,_final) )
                return true;
        }
    }
    return false;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值