首页 > 代码库 > HDU 4888 Redraw Beautiful Drawings(2014 Multi-University Training Contest 3)

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;}