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

题意:给定n*m个格子,每个格子能填0-k 的整数。然后给出每列之和和每行之和,问有没有解,有的话是不是唯一解,是唯一解输出方案。

思路:网络流,一共 n+m+2个点   源点 到行连流量为 所给的 当前行之和。    每行 连到每一列 一条流量为  k的边,每列到汇点连 列和。如果流量等于总和则有解,反之无解(如果列总和不等于行总和也无解)。  判断方案是否唯一 找残留网络是否存在长度大于2的环即可,有环说明不唯一。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include <iostream>
#include<climits>
using namespace std;
const int N = 1000;
const int M = 1000000;
int n;
int ecnt, head[N], nx[M], to[M], va[M], cur_edge[N];
int source, target, flow, pre[N], lev[N], qu[N], sign;
void addedge(int u, int v, int w) {
    to[ecnt] = v;
    nx[ecnt] = head[u];
    va[ecnt] = w;
    head[u] = ecnt++;
}
bool bfs(int s, int t) {
    std::fill(lev, lev + n, -1);
    sign = t;
    lev[t] = 0;
    int st = 0, ed = 0;
    qu[ed++] = t;
    while (st != ed && lev[s] == -1) {
        int u = qu[st++];
        for (int i = head[u]; i != -1; i = nx[i]) {
            if (va[i ^ 1] > 0 && lev[to[i]] == -1) {
                lev[to[i]] = lev[u] + 1;
                qu[ed++] = to[i];
            }
        }
    }
    return lev[s] != -1;
}
void push() {
    int delta = INT_MAX, u, p;
    for (u = target; u != source; u = to[p ^ 1]) {
        p = pre[u];
        delta = std::min(delta, va[p]);
    }
    for (u = target; u != source; u = to[p ^ 1]) {
        p = pre[u];
        va[p] -= delta;
        if (!va[p]) {//注意double时要改
            sign = to[p ^ 1];
        }
        va[p ^ 1] += delta;
    }
    flow += delta;
}
void dfs(int u) {
    if (u == target)
        push();
    else {
        for (int i = cur_edge[u]; i != -1; i = nx[i]) {
            if (va[i] > 0 && lev[u] == lev[to[i]] + 1) {
                pre[to[i]] = i;
                dfs(to[i]);
                if (lev[sign] > lev[u]) {
                    return;
                }
                sign = target;
            }
        }
        lev[u] = -1;
    }
}
void dinic(int s, int t, int node_cnt) {
    source = s;
    target = t;
    n = node_cnt;

    //construct graph

    flow = 0;
    while (bfs(source, target)) {
        for (int i = 0; i < n; ++i) {
            cur_edge[i] = head[i];
        }
        dfs(source);
    }

}
int nc, kc, mc, sum1, sum2;
int r[410], c[410];
void init() {
    sum1 = sum2 = 0;
    for (int i = 0; i < nc; ++i) {
        scanf("%d", &r[i]);
        sum1 += r[i];
    }
    for (int i = 0; i < mc; ++i) {
        scanf("%d", &c[i]);
        sum2 += c[i];
    }
}
int flag = 0;
bool bo[1000];
bool bb[1000];
int cas[350000];
int ri = 0;
void gao(int now, int fa) {//找环
    if(flag)return;
    //printf("->%d ",now);
    bo[now] = true;
    for (int i = head[now]; i != -1; i = nx[i]) {
        int u = to[i];
        if (u == fa)
            continue;
        if (va[i] == 0)
            continue;

        //    printf(" {%d %d}\n",now,u);
        if (bb[u]) {
            //    puts("fuck");
            flag = 1;
            return;
        }
        if (cas[i] == ri)
            continue;
        cas[i] = ri;
        //if(bo[u])continue;
        bb[u] = true;
        gao(u, now);
        bb[u] = false;
    }
}
void solve() {
    if (sum1 != sum2) {
        puts("Impossible");
        return;
    }
    std::fill(head, head + mc + nc + 5, -1);
    ecnt = 0;
    int s, t;
    s = nc + mc;
    t = s + 1;
    //    printf("st:%d %d\n",s,t);
    for (int i = 0; i < nc; ++i) {
        for (int j = 0; j < mc; ++j) {

            //        printf("[%d %d]\n",i,j+nc);
            addedge(i, j + nc, kc);
            addedge(j + nc, i, 0);
        }
    }
    for (int i = 0; i < nc; ++i) {
        //    printf("[%d %d]\n",s,i);
        addedge(s, i, r[i]);
        addedge(i, s, 0);
    }
    for (int i = 0; i < mc; ++i) {

        //    printf("[%d %d]\n",i+nc,t);
        addedge(i + nc, t, c[i]);
        addedge(t, i + nc, 0);
    }
    dinic(s, t, t + 2);
    //    printf("flow:%d\n",flow);
    if (flow == sum1) {

        memset(bo, 0, sizeof(bo));
        memset(bb, 0, sizeof(bb));
        flag = 0;
        for (int i = 0; i <= t; ++i) {
            if(flag)break;
            bb[i] = true;
            gao(i, -1);
            bb[i] = false;
        }
        if (flag)
            puts("Not Unique");
        else {
            puts("Unique");
            for (int i = 0; i < nc; ++i) {
                for (int j = 0; j < mc; ++j) {
                    int now = i * mc + j;
                    printf("%d", va[now << 1 | 1]);
                    if (j == mc - 1)
                        puts("");
                    else
                        printf(" ");
                }
            }
        }
    } else
        puts("Impossible");
}
int main() {
    memset(cas, 0, sizeof(cas));
    while (scanf("%d%d%d", &nc, &mc, &kc) != EOF) {
        ++ri;
        init();
        solve();
    }
    return 0;
}

HDU 4888 Redraw Beautiful Drawings(2014 Multi-University Training Contest 3),布布扣,bubuko.com

时间: 2024-10-20 16:12:21

HDU 4888 Redraw Beautiful Drawings(2014 Multi-University Training Contest 3)的相关文章

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

题意:给一个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(网络流求矩阵的解)

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

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

Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Alice and Bob are playing together. Alice is crazy about art and she has visited many museums around the world. She has

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

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

hdu 4888 Redraw Beautiful Drawings

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

hdu 4888 Redraw Beautiful Drawings 最大流

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