HDUOJ--4888--Redraw Beautiful Drawings【isap】网络流+判环

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4888

题意:一个矩阵,限定每行行和、列和,每个格子数字不超过k,问矩阵是否存在,如存在判断有单解还是多解。

思路:之前多校的题目,那时候还不会网络流,现在A掉了,矩阵的建图模型,判断网络流是否可行只要判断最大流是否等于总行和或总列和即可,判环是看的别人的解题报告,方法是使用dfs查找残余网络中是否有还存在容量的弧形成了环,如果有,说明可以通过这个环改变容量网络内部的增广路方式,而源汇的流量是不会变的,就说明存在多解。如果没有环,就是单一解。

建图:源点向每个行节点连弧,容量为该行行和,每个列节点向汇点连边,容量为每个列和,每个行节点与每个列节点之间连边,容量为k。

细节:我用的我之前AC过题目的isap模板,但是WA了,我debug之后发现错误不会在建图和判环里,然后就和别人的isap代码对照,发现了一个不一样的地方,改之AC,不懂为何,不一样的地方代码中有注释。我的理解nn个点,源点src的层次是0,则最大的层次应该就是nn-1,但是minm初始化为nn-1是WA,初始化为nn就AC了。理论上应该是初始化大于等于nn-1都是可以的,以后还是就初始化为nn吧避免莫名其妙的WA。

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 50100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define LLINF 0x7FFFFFFFFFFFFFFF
#define seed 131
#define MOD 1000000007
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct node{
    int u,v,w,next;
}edge[500000];
int head[820],dist[820],cur[820],fa[820],num[820],vis[820];
int n,m,k,cnt,nn,src,sink;
void add_edge(int a,int b,int c){
    edge[cnt].u = a;
    edge[cnt].v = b;
    edge[cnt].w = c;
    edge[cnt].next = head[a];
    head[a] = cnt++;
}
void bfs()
{
    int x,i,j;
    queue<int> q;
    memset(dist,-1,sizeof(dist));
    memset(num,0,sizeof(num));
    q.push(sink);
    dist[sink] = 0;
    num[0] = 1;
    while(!q.empty()){
        x = q.front();
        q.pop();
        for(i=head[x];i!=-1;i=edge[i].next){
            if(dist[edge[i].v]<0){
                dist[edge[i].v] = dist[x] + 1;
                num[dist[edge[i].v]]++;
                q.push(edge[i].v);
            }
        }
    }
}

int augment()
{
    int x=sink,a=INF;
    while(x!=src){
        a = min(a,edge[fa[x]].w);
        x = edge[fa[x]].u;
    }
    x=sink;
    while(x!=src){
        edge[fa[x]].w -= a;
        edge[fa[x]^1].w += a;
        x = edge[fa[x]].u;
    }
    return a;
}

int isap()
{
    int i,x,ok,minm,flow=0;
    bfs();
    for(i=0;i<=nn+5;i++) cur[i] = head[i];
    x=src;
    while(dist[src]<nn){
        if(x==sink){
            flow += augment();
            x = src;
        }
        ok=0;
        for(i=cur[x];i!=-1;i=edge[i].next){
            if(edge[i].w && dist[x]==dist[edge[i].v]+1){
                ok=1;
                fa[edge[i].v] = i;
                cur[x] = i;
                x = edge[i].v;
                break;
            }
        }
        if(!ok){
            minm = nn;	//minm = nn - 1 就WA
            for(i=head[x];i!=-1;i=edge[i].next)
                if(edge[i].w && dist[edge[i].v]<minm)   minm=dist[edge[i].v];
            if(--num[dist[x]]==0)break;
            num[dist[x]=minm+1]++;
            cur[x]=head[x];
            if(x!=src)  x=edge[fa[x]].u;
        }
    }
    return flow;
}
bool dfs(int u,int pre){
    int i,j;
    if(vis[u])  return true;
    vis[u] = 1;
    for(i=head[u];i!=-1;i=edge[i].next){
        if(edge[i].w>0&&edge[i].v!=pre&&dfs(edge[i].v,u))
            return true;
    }
    vis[u] = 0;
    return false;
}
int row[410],col[410];
int ans[420][420];
int main(){
    int i,j;
    int sumr,sumc;
    while(scanf("%d%d%d",&n,&m,&k)!=EOF){
        memset(head,-1,sizeof(head));
        sumr = sumc = 0;
        cnt = 0;
        src = 0;
        sink = n + m + 1;
        nn = sink + 1;
        for(i=1;i<=n;i++){
            scanf("%d",&row[i]);
            sumr += row[i];
            add_edge(src,i,row[i]);
            add_edge(i,src,0);
            for(j=1;j<=m;j++){
                add_edge(i,j+n,k);
                add_edge(j+n,i,0);
            }
        }
        for(i=1,j=n+1;i<=m;j++,i++){
            scanf("%d",&col[i]);
            sumc += col[i];
            add_edge(j,sink,col[i]);
            add_edge(sink,j,0);
        }
        if(sumr!=sumc){
            puts("Impossible");
            continue;
        }
        int flag = 0;
        int flow = isap();
        if(flow!=sumr){
            puts("Impossible");
            continue;
        }
        memset(vis,0,sizeof(vis));
        for(i=1;i<=n;i++){
            if(dfs(i,-1)){
                flag = 1;
                break;
            }
        }
        if(flag){
            puts("Not Unique");
            continue;
        }
        puts("Unique");
        memset(ans,0,sizeof(ans));
        for(i=1;i<=n;i++){
            for(j=head[i];j!=-1;j=edge[j].next){
                int u = edge[j].v;
                if(u>n&&u<=n+m){
                    ans[i][u-n] = k - edge[j].w;
                }
            }
        }
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                if(j>1) printf(" ");
                printf("%d",ans[i][j]);
            }
            printf("\n");
        }
    }
    return 0;
}
时间: 2024-10-14 09:55:48

HDUOJ--4888--Redraw Beautiful Drawings【isap】网络流+判环的相关文章

hdu4888 Redraw Beautiful Drawings 最大流+判环

hdu4888 Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2007    Accepted Submission(s): 447 Problem Description Alice and Bob are playing together. Alice is crazy abou

HDU 4888 Redraw Beautiful Drawings(网络流求矩阵的解)

论文<为什么很多网络流问题总有整数解>http://diaorui.net/archives/189: 参考:http://www.cnblogs.com/yuiffy/p/3929369.html 题意:n*m的矩阵,给出每行的和以及每列的和,判断这样的矩阵是否存在,若存在,是否唯一:若唯一,输出解: 思路:网络流,最大流+判环.网络流常用于求多项式整数解. #include<cstdio> #include<cstring> #include<algorith

HDU 4888 Redraw Beautiful Drawings(最大流+判最大流网络是否唯一)

Problem Description Alice and Bob are playing together. Alice is crazy about art and she has visited many museums around the world. She has a good memory and she can remember all drawings she has seen. Today Alice designs a game using these drawings

HDU 4888 (杭电多校#3)Redraw Beautiful Drawings(网络流之最大流)

题目地址:HDU 4888 自己之所以弱真心是态度的问题,以后不能再偷懒了!!那次这个题一直没补,结果这次又遇到了..还有这次遇到的最小割权闭合问题,也一直没刷,所以这次遇到了也不会,连是最小割都不知道!!(突然想起来前面还有好多题拖到现在也没做...T U T)以后绝不能再拖拉了! 这题的建图是很容易的,主要是判断唯一性不好判断.这里是用的dfs找环来判断是否唯一,因为假如有环的话,说明环 中的数字是可以相互流动而且可以保证解依然正确.. 代码如下: #include <cstdio> #i

【HDU】4888 Redraw Beautiful Drawings 网络流【推断解是否唯一】

传送门:pid=4888">[HDU]4888 Redraw Beautiful Drawings 题目分析: 比赛的时候看出是个网络流,可是没有敲出来.各种反面样例推倒自己(究其原因是不愿意写暴力推断的).. 首先是简单的行列建边.源点向行建边.容量为该行元素和,汇点和列建边.容量为该列元素和.全部的行向全部的列建边,容量为K. 跑一次最大流.满流则有解,否则无解. 接下来是推断解是否唯一. 这个题解压根没看懂.还是暴力大法好. 最简单的思想就是枚举在一个矩形的四个端点.设A.D为主对角

HDU 4888 Redraw Beautiful Drawings 网络流 建图

题意: 给定n, m, k 下面n个整数 a[n] 下面m个整数 b[n] 用数字[0,k]构造一个n*m的矩阵 若有唯一解则输出这个矩阵,若有多解输出Not Unique,若无解输出Impossible 思路:网络流,,, n行当成n个点,m列当成m个点 从行-列连一条流量为k的边,然后源点-行连一条a[i]的边, 列-汇点 流量为b[i] 瞎了,该退役了 T^T #include<stdio.h> #include<string.h> #include<iostream&

HDU 4888 Redraw Beautiful Drawings (2014-多校3-1002,最大流,判最大流有多解)

题目: http://acm.hdu.edu.cn/showproblem.php?pid=4888 题意: 给一个n*m的矩阵的n行之和和m列之和以及限制k,使用0-k的数字填充矩阵使得其行与列之和为给定值 如果不行则输出Impossible 如果有多解则输出Not Unique 如果有一解则输出Unique,并输出构造的矩阵 方法: 最大流,判最大流有多解 1.建图: 每一行一个点,每一列一个点 源点与第i个行点连边,权值为第i行之和 第j个列点与汇点连边,权值为第j行之和 第i个行点与第j

HDU 4888 Redraw Beautiful Drawings(2014 Multi-University Training Contest 3)

题意:给定n*m个格子,每个格子能填0-k 的整数.然后给出每列之和和每行之和,问有没有解,有的话是不是唯一解,是唯一解输出方案. 思路:网络流,一共 n+m+2个点   源点 到行连流量为 所给的 当前行之和.    每行 连到每一列 一条流量为  k的边,每列到汇点连 列和.如果流量等于总和则有解,反之无解(如果列总和不等于行总和也无解).  判断方案是否唯一 找残留网络是否存在长度大于2的环即可,有环说明不唯一. #include<cstdio> #include<cstring&

【多校赛第三场】Redraw Beautiful Drawings【网络流】【谜のWA】

参考题解:http://blog.csdn.net/qian99/article/details/38276887 #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <queue> #include <vector> #include <algorithm>

hdoj 4888 Redraw Beautiful Drawings 【最大流满流+唯一性判断】

题目:hdoj 4888 Redraw Beautiful Drawings 分类:最大流满流 , 最大流唯一性 来源:2014 Multi-University Training Contest 3 题意:一个矩阵的每行每列的和都知道,然后让你求能不能填,是否唯一,唯一的话输出解. 分析:这个题目能看出来是最大流,但是难点有2. 首先:题中矩阵400 * 400 ,好在题目中矩阵和没有特殊要求,所以可以直接以行列建图,建图方案: 1. 源点 -> 每一行对应的点,流量限制为该行的和 2. 每一