hdu 4888 Redraw Beautiful Drawings

题目是一个矩阵,每行每列的数字的和都有一个上限,问是否存在可行方案,并且可行方案是否唯一。

第一问比较简单,行列建图,s到每个行节点容量为该行上限,每个列节点连接到t,容量为该列的上限,求最大流,如果满流则有可行方案。第二问就是判断最大流是否唯一,就是在原图中找一个环(经过一条边后不能马上走反向边),环上的边cap-flow都大于0。如果有这个环,那么不唯一,否则唯一。因为流量为k的两个流量图的差别肯定是一个个的环,否则流量不相同,只要按照这个环进行流量的重新分配就可以找到另一个方案。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define maxn 1000
#define INF 10000000
struct Edge
{
    int from, to, cap, flow;
}edges[360000];

int n, m, s, t, kk, cnt;
vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
bool vis[maxn];        // BFS使用
int d[maxn];           // 从起点到i的距离
int cur[maxn];         // 当前弧指针
int map[410][410];
void AddEdge(int from, int to, int cap)
{
    edges[cnt].from=from;
    edges[cnt].to=to;
    edges[cnt].cap=cap;
    edges[cnt].flow=0;
    G[from].push_back(cnt);
    cnt++;
    edges[cnt].from=to;
    edges[cnt].to=from;
    edges[cnt].cap=0;
    edges[cnt].flow=0;
    G[to].push_back(cnt);
    cnt++;
}
bool BFS()
{
    memset(vis, 0, sizeof(vis));
    queue<int> Q;
    Q.push(s);
    vis[s] = 1;
    d[s] = 0;
    while(!Q.empty())
    {
        int x = Q.front(); Q.pop();
        for(int i = 0; i < G[x].size(); i++)
        {
            Edge& e = edges[G[x][i]];
            if(!vis[e.to] && e.cap > e.flow)
            {
                vis[e.to] = 1;
                d[e.to] = d[x] + 1;
                Q.push(e.to);
            }
        }
    }
    return vis[t];
}
int DFS(int x, int a)
{
    if(x == t || a == 0) return a;
    int flow = 0, f;
    for(int& i = cur[x]; i < G[x].size(); i++)
    {
        Edge& e = edges[G[x][i]];
        if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0)
        {
            e.flow += f;
            edges[G[x][i]^1].flow -= f;
            flow += f;
            a -= f;
            if(a == 0) break;
        }
    }
    return flow;
}
int Maxflow()
{
    int flow = 0;
    while(BFS())
    {
        memset(cur, 0, sizeof(cur));
        flow += DFS(s, INF);
    }
    return flow;
}

int dfs(int x,int fa)
{
    int i;
    for(i=0;i<G[x].size();i++)
    {
        int v=edges[G[x][i]].to;
        int cap=edges[G[x][i]].cap;
        int flow=edges[G[x][i]].flow;
        if(v==fa) continue;
        if(v!=s&&v!=t&&cap-flow)
        {
            if(vis[v]) return 1;
            vis[v]=1;
            if(dfs(v,x)) return 1;
            vis[v]=0;
        }
    }
    return 0;
}
int main()
{
    while(scanf("%d%d%d",&n,&m,&kk)!=EOF)
    {
        int i,j,x;
        int flag=0;
        int sum1=0,sum2=0;
        s=0;t=n+m+1;cnt=0;
        for(i=0;i<=t;i++) G[i].clear();
        for(i=1;i<=n;i++) {scanf("%d",&x); sum1+=x; AddEdge(s,i,x);}
        for(i=1;i<=m;i++) {scanf("%d",&x); sum2+=x; AddEdge(i+n,t,x);}
        if(sum1!=sum2) {printf("Impossible\n"); continue;}
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                AddEdge(i,j+n,kk);
        if(Maxflow()!=sum1) {printf("Impossible\n"); continue;}
        memset(vis,0,sizeof(vis));
        for(i=1;i<=n;i++)
        {
            vis[i]=1;
            if(dfs(i,-1))
            {
                flag=1;
                break;
            }
            vis[i]=0;
        }
        if(flag==1) printf("Not Unique\n");
        else
        {
            printf("Unique\n");
            for(j=1;j<=n;j++)
                for(i=0;i<G[j].size();i++)
                {
                    int v=edges[G[j][i]].to;
                    if(v!=s)
                        map[j][v-n]=edges[G[j][i]].flow;
                }
            for(i=1;i<=n;i++)
            {
                printf("%d",map[i][1]);
                for(j=2;j<=m;j++)
                    printf(" %d",map[i][j]);
                printf("\n");
            }
        }
    }
    return 0;
}
时间: 2024-12-28 16:39:17

hdu 4888 Redraw Beautiful Drawings的相关文章

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 Multi-University Training Contest 3)

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

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 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(最大流,判环)

http://acm.hdu.edu.cn/showproblem.php?pid=4888 加入一个源点与汇点,建图例如以下: 1. 源点 -> 每一行相应的点,流量限制为该行的和 2. 每一行相应的点 -> 每一列相应的点,流量限制为 K 3. 每一列相应的点 -> 汇点,流量限制为该列的和 求一遍最大流,若最大流与矩阵之和相等,说明有解,否则无解.推断唯一解,是推断残量网络中是否存在一个长度大于2的环.若存在说明有多解,否则有唯一解,解就是每条边行i->列j的流量. #inc

hdu - 4888 - Redraw Beautiful Drawings(最大流)

题意:给一个N行M列的数字矩阵的行和以及列和,每个元素的大小不超过K,问这样的矩阵是否存在,是否唯一,唯一则求出各个元素N(1 ≤ N ≤ 400) , M(1 ≤ M ≤ 400), K(1 ≤ K ≤ 40). 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4888 -->>建图: 1)超级源S = 0,超级汇T = N + M + 1: 2)S到每个行和各连一条边,容量为该行行和: 3)每个行和到每个列和各连一条边,容量为K: 4)每个列和

hdu 4888 Redraw Beautiful Drawings 最大流

好难好难,将行列当成X和Y,源汇点连接各自的X,Y集,容量为行列的和,相当于从源点流向每一行,然后分配流量给每一列,最后流入汇点,这样执意要推断最后是否满流,就知道有没有解,而解就是每一行流向每一列多少流量. 关键在于怎么推断多解的情况.我想不到啊T_T 题讲解,找到一个长度大于2的环. 想了一想,也就是找到还有剩余流量的环,假设找到了,我就能够把当中一条边的流量转移,由于是一个环,所以它又会达到平衡,不会破坏最大流,可是这样转移后,解就多了一种,所以仅仅要推断是否有一个长度大于2的环就够了.

hdu 4888 Redraw Beautiful Drawings 网络流

题目链接 一个n*m的方格, 里面有<=k的数, 给出每一行所有数的和, 每一列所有数的和, 问你能否还原这个图, 如果能, 是否唯一, 如果唯一, 输出还原后的图. 首先对行列建边, 源点向行建边, 权值为这一行的和, 列向汇点建边, 权值为列和, 每一行向每一列建边, 权值为k, 因为上限是k. 然后跑一遍最大流, 如果最大流和所有行的和以及所有列的和相等, 那么可以还原. 判断是否唯一, 用判环的方式, 对图中每一个点dfs, 如果存在环, 说明原图不唯一. 原图每个格子的值等于k-这个格

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