HDU 4975 A simple Gaussian elimination problem. 网络流+矩阵上的dp

随机输出保平安啊

和hdu4888一个意思,先跑个网络流然后dp判可行。

==n^3的dp过不了,所以把n改成200。

==因为出题人没有把多解的情况放在200*200以外的矩阵。

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

const int MAX_N = 1207;
const int MAX_E = MAX_N * MAX_N * 5;
const int INF = 0x3f3f3f3f;

struct Edge {
    int v, nxt;
    long long cap;
    Edge() {

    }
    Edge(int _v, int _nxt, long long _cap) {
        v = _v, nxt = _nxt, cap = _cap;
    }
};

Edge G[MAX_E];
int edgecnt, head[MAX_N];
int gap[MAX_N], d[MAX_N];

struct Isap {
    int n, s, t;
    void init(int n, int s, int t) {
        this->n = n, this->s = s, this->t = t;
        edgecnt = 0;
        memset(head, -1, sizeof head);
    }
    void addedge(int u, int v, long long cap) {
        G[edgecnt] = Edge(v, head[u], cap);
        head[u] = edgecnt++;
        G[edgecnt] = Edge(u, head[v], 0);
        head[v] = edgecnt++;
    }
    long long dfs(int u, long long tot) {
        if (u == t) return tot;
        int minh = n - 1;
        long long leave = tot;
        for (int i = head[u]; ~i && leave; i = G[i].nxt) {
            int v = G[i].v;
            if (G[i].cap > 0) {
                if (d[v] + 1 == d[u]) {
                    long long c = dfs(v, min(leave, G[i].cap));
                    G[i].cap -= c;
                    G[i ^ 1].cap += c;
                    leave -= c;
                    if (d[s] >= n)
                        return tot - leave;
                }
                minh = min(minh, d[v]);
            }
        }
        if (leave == tot) {
            --gap[d[u]];
            if (gap[d[u]] == 0) d[s] = n;
            d[u] = minh + 1;
            ++gap[d[u]];
        }
        return tot - leave;
    }
    long long maxFlow() {
        long long ret = 0;
        memset(gap, 0, sizeof gap);
        memset(d, 0, sizeof d);
        gap[0] = n;
        while (d[s] < n) {
            ret += dfs(s, INF);
        }
        return ret;
    }
};

int n, m, k;
int mat[MAX_N][MAX_N];
int c[MAX_N][MAX_N];

inline bool rd(int &n){
    int x = 0, tmp = 1;
    char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}    

int main() {
    int T;
    scanf("%d", &T);
    int cas = 0;
    while (T-- > 0) {
        Isap ans;
        scanf("%d%d", &n, &m);
        k = 9;
        ans.init(n + m + 2, 0, n + m + 1);
        int s = 0, t = n + m + 1;
        long long sum1 = 0, sum2 = 0;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                ans.addedge(i, n + j, k);
            }
        }
        for (int i = 1; i <= n; ++i) {
            int rowSum = 0;
            rd(rowSum);
            sum1 += rowSum;
            ans.addedge(0, i, rowSum);
        }
        for (int i = 1; i <= m; ++i) {
            int colSum = 0;
            rd(colSum);
            sum2 += colSum;
            ans.addedge(n + i, t, colSum);
        }
        int q = ans.maxFlow();
        printf("Case #%d: ", ++cas);
        if (sum1 != sum2 || q != sum1) puts("So naive!");
        else {
            int edge = 0;
            n = min(n, 200);
            m = min(m, 200);
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j, edge += 2) {
                    mat[i][j] = G[edge ^ 1].cap;
                }
            }
            memset(c, false, sizeof c);
            bool f = false;
            for (int i = 1; i <= n; ++i) {
                for (int j = 1; j <= m; ++j) {
                    for (int l = j + 1; l <= m; ++l) {
                        bool f1 = false, f2 = false;
                        if (mat[i][j] != k && mat[i][l] != 0) {// column j could add, column l could dec
                            if (c[l][j]) {
                                l = m + 1, j = m + 1, i = n + 1;
                                f = true;
                            }
                            f1 = true;
                        }
                        if (mat[i][j] != 0 && mat[i][l] != k) {// column l could add, column j could dec
                            if (c[j][l]) {
                                l = m + 1, j = m + 1, i = n + 1;
                                f = true;
                            }
                            f2 = true;
                        }
                        if (f1) c[j][l] = true;
                        if (f2) c[l][j] = true;
                    }
                }
            }
            if (f) puts("So young!");
            else {
                puts("So simple!");
            }
        }
    }
    return 0;
}

HDU 4975 A simple Gaussian elimination problem. 网络流+矩阵上的dp

时间: 2024-12-17 03:52:38

HDU 4975 A simple Gaussian elimination problem. 网络流+矩阵上的dp的相关文章

hdu 4975 A simple Gaussian elimination problem.(网络流,判断矩阵是否存在)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4975 Problem Description Dragon is studying math. One day, he drew a table with several rows and columns, randomly wrote numbers on each elements of the table. Then he counted the sum of each row and col

HDU 4975 A simple Gaussian elimination problem.(网络最大流)

http://acm.hdu.edu.cn/showproblem.php?pid=4975 A simple Gaussian elimination problem. Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 669    Accepted Submission(s): 222 Problem Description Drag

hdu 4975 A simple Gaussian elimination problem.(网络流,推断矩阵是否存在)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4975 Problem Description Dragon is studying math. One day, he drew a table with several rows and columns, randomly wrote numbers on each elements of the table. Then he counted the sum of each row and col

HDU 4975 A simple Gaussian elimination problem.

http://acm.hdu.edu.cn/showproblem.php?pid=4975 题意:同HDU 4888.给N行M列,每行之和,每列之和,判断矩阵是不是唯一. 题解:网络流.源点和每行之和建边,容量为和:汇点和没列之和建边,容量为和:行之和和列之和建边,容量为9(每位只能是0~9). 判断可行性:行之和的和是否等于列之和的和:是否满流. 判断唯一解:残留网络里是否有长度大于等于2的环 1 #include <cstdio> 2 #include <cstring> 3

hdu 4975 A simple Gaussian elimination problem 最大流+找环

原题链接 http://acm.hdu.edu.cn/showproblem.php?pid=4975 这是一道很裸的最大流,将每个点(i,j)看作是从Ri向Cj的一条容量为9的边,从源点除法连接每个Ri,再从每个Ci连接至汇点.如若最大流不是滿流,则问题无解.这道题的关键就是在于如何判断是否有多解.考虑这样一个事实,若残余网络上有多个点构成一个环,那么流量可在这个环上调整,某条边上多余的流量可以被环上的其他的边弥补回来.所以如果残余网络上存在一个边数大于2的环,那么问题则是多解.我判断是否有环

hdu - 4975 - A simple Gaussian elimination problem.(最大流)

题意:给一个N行M列的数字矩阵的行和以及列和,每个元素的大小不超过9,问这样的矩阵是否存在,是否唯一N(1 ≤ N ≤ 500) , M(1 ≤ M ≤ 500). 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4975 -->>方法如:http://blog.csdn.net/scnu_jiechao/article/details/40658221 先做hdu - 4888,再来做此题的时候,感觉这题好 SB 呀,将代码提交后自己就 SB 了

【最大流】HDU 4975 A simple Gaussian elimination problem

通道 题意:n*m的矩阵,每个格子可以是0~9,给出各行的和和各列的和,求格子数字唯一方案,或判断无解或不唯一 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <queue> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int MAX_N = 1207; 10 const

hdoj 4975 A simple Gaussian elimination problem. 【最大流唯一性判断】

题目:hdoj 4975 A simple Gaussian elimination problem. 这个题目跟hdoj 4888 一样,只是数据加强了一点,这个题目确实出的不好,尤其数据,争议比较大,但是同时也说明优化有时候还是很有用的. 不懂的可以看这个讲解:点击 这个题目只是加了一点优化,就是判断的时候加入是行和为0,或者满的话,就跳出不用判断,然后就300ms过了.真心牛 AC代码: #include <cstdio> #include <cstring> #includ

HDOJ 4975 A simple Gaussian elimination problem.

和HDOJ4888是一样的问题,最大流推断多解 1.把ISAP卡的根本出不来结果,仅仅能把全为0或者全为满流的给特判掉...... 2.在残量网络中找大于2的圈要用一种类似tarjian的方法从汇点開始找,推断哪些点没有到汇点 A simple Gaussian elimination problem. Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submiss