A simple Gaussian elimination problem.(hdu4975)网络流+最大流

A simple Gaussian elimination problem.

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 728 Accepted Submission(s):
241

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 column. Since he thought the map will be
useless after he got the sums, he destroyed the table after that.

However
Dragon‘s mom came back and found what he had done. She would give dragon a feast
if Dragon could reconstruct the table, otherwise keep Dragon hungry. Dragon is
so young and so simple so that the original numbers in the table are one-digit
number (e.g. 0-9).

Could you help Dragon to do that?

Input

The first line of input contains only one integer,
T(<=30), the number of test cases. Following T blocks, each block describes
one test case.

There are three lines for each block. The first line
contains two integers N(<=500) and M(<=500), showing the number of rows
and columns.

The second line contains N integer show the sum of each
row.

The third line contains M integer show the sum of each column.

Output

Each output should occupy one line. Each line should
start with "Case #i: ", with i implying the case number. For each case, if we
cannot get the original table, just output: "So naive!", else if we can
reconstruct the table by more than one ways, you should output one line contains
only: "So young!", otherwise (only one way to reconstruct the table) you should
output: "So simple!".

Sample Input

3

1 1

5

5

2 2

0 10

0 10

2 2

2 2

2 2

Sample Output

Case #1: So simple!

Case #2: So naive!

Case #3: So young!

网络流+最大流

题意:输入N*M的表格,在里面输入0-9内的数字,是的每行每列相加等于对应的值,如果表格唯一就输出Case #%d: So simple!;如果表格不唯一,则输出Case #%d: So young!;如果表格不存在,就输出Case #%d: So naive!

题目和hdu4888类似;

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <numeric>
using namespace std;
typedef long long LL;
const int MAXN = 510;
const int MAXV = MAXN << 1;
const int MAXE = 2 * MAXN * MAXN;
const int INF = 0x3f3f3f3f;
struct ISAP
{
    int head[MAXV], cur[MAXV], gap[MAXV], dis[MAXV], pre[MAXV];
    int to[MAXE], next[MAXE], flow[MAXE];
    int n, ecnt, st, ed;
    void init(int n)
    {
        this->n = n;
        memset(head + 1, -1, n * sizeof(int));
        ecnt = 0;
    }
    void add_edge(int u, int v, int c)
    {
        to[ecnt] = v;
        flow[ecnt] = c;
        next[ecnt] = head[u];
        head[u] = ecnt++;
        to[ecnt] = u;
        flow[ecnt] = 0;
        next[ecnt] = head[v];
        head[v] = ecnt++;

    }
    void bfs()
    {
        memset(dis + 1, 0x3f, n * sizeof(int));
        queue<int> que;
        que.push(ed);
        dis[ed] = 0;
        while(!que.empty())
        {
            int u = que.front();
            que.pop();
            gap[dis[u]]++;
            for(int p = head[u]; ~p; p = next[p])
            {
                int v = to[p];
                if(flow[p ^ 1] && dis[u] + 1 < dis[v])
                {
                    dis[v] = dis[u] + 1;
                    que.push(v);
                }
            }
        }
    }  int max_flow(int ss, int tt)
    {
        st = ss, ed = tt;
        int ans = 0, minFlow = INF;
        for(int i = 0; i <= n; ++i)
        {
            cur[i] = head[i];
            gap[i] = 0;

        }
        bfs();
        int u = pre[st] = st;
        while(dis[st] < n)
        {
            bool flag = false;
            for(int &p = cur[u]; ~p; p = next[p])
            {
                int v = to[p];
                if(flow[p] && dis[u] == dis[v] + 1)
                {
                    flag = true;
                    minFlow = min(minFlow, flow[p]);
                    pre[v] = u;
                    u = v;
                    if(u == ed)
                    {
                        ans += minFlow;
                        while(u != st)
                        {
                            u = pre[u];
                            flow[cur[u]] -= minFlow;
                            flow[cur[u] ^ 1] += minFlow;

                        }
                        minFlow = INF;

                    }
                    break;

                }

            }
            if(flag) continue;
            int minDis = n - 1;
            for(int p = head[u]; ~p; p = next[p])
            {
                int &v = to[p];
                if(flow[p] && dis[v] < minDis)
                {
                    minDis = dis[v];
                    cur[u] = p;

                }
            }
            if(--gap[dis[u]] == 0) break;
            ++gap[dis[u] = minDis + 1];
            u = pre[u];

        }
        return ans;

    } int stk[MAXV], top;
    bool sccno[MAXV], vis[MAXV];
    bool dfs(int u, int f, bool flag)
    {
        vis[u] = true;
        stk[top++] = u;
        for(int p = head[u]; ~p; p = next[p]) if(flow[p])
            {
                int v = to[p];
                if(v == f) continue;
                if(!vis[v])
                {
                    if(dfs(v, u, flow[p ^ 1])) return true;

                }
                else if(!sccno[v]) return true;

            }
        if(!flag)
        {
            while(true)
            {
                int x = stk[--top];
                sccno[x] = true;
                if(x == u) break;

            }

        }
        return false;

    }
    bool acycle()
    {
        memset(sccno + 1, 0, n * sizeof(bool));
        memset(vis + 1, 0, n * sizeof(bool));
        top = 0;
        return dfs(ed, 0, 0);

    }
} G;
int row[MAXN], col[MAXN];
int mat[MAXN][MAXN];
int n, m, k, ss, tt;
void solve()
{
    int sumr = accumulate(row + 1, row + n + 1, 0);
    int sumc = accumulate(col + 1, col + m + 1, 0);
    if(sumr != sumc)
    {
        puts("So naive!");
        return ;

    }
    int res = G.max_flow(ss, tt);
    if(res != sumc)
    {
        puts("So naive!");
        return ;

    }
    if(G.acycle())
    {
        puts("So young!");

    }
    else
    {
        puts("So simple!");
    }

}
int main()
{
    int T,Case;
    scanf("%d",&T);

    for(Case=1;Case<=T;Case++)
    {
        scanf("%d%d",&n,&m);
        k=9;
        for(int i = 1; i <= n; ++i) scanf("%d", &row[i]);
        for(int i = 1; i <= m; ++i) scanf("%d", &col[i]);
        ss = n + m + 1, tt = n + m + 2;
        printf("Case #%d: ",Case);
        G.init(tt);
        for(int i = 1; i <= n; ++i) G.add_edge(ss, i, row[i]);
        for(int i = 1; i <= m; ++i) G.add_edge(n + i, tt, col[i]);
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= m; ++j)
            {
                mat[i][j] = G.ecnt ^ 1;
                G.add_edge(i, n + j, k);
            }
        }
        solve();

    }
}

时间: 2024-11-10 07:23:38

A simple Gaussian elimination problem.(hdu4975)网络流+最大流的相关文章

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 (杭电多校 #10 1005题)A simple Gaussian elimination problem.(网络流之最大流)

题目地址:HDU 4975 对这题简直无语...本来以为这题要用什么更先进的方法,结果还是老方法,这么卡时间真的好吗....比赛的时候用了判环的方法,一直TLE..后来换了矩阵DP的方式,加了加剪枝就过了..无语了.. 代码如下: #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cstdio> #include <

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. 网络流+矩阵上的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 = 12

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

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

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

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

A simple Gaussian elimination problem.

hdu4975:http://acm.hdu.edu.cn/showproblem.php?pid=4975 题意:给你一个n*m的矩阵,矩阵中的元素都是0--9,现在给你这个矩阵的每一行和每一列的和,问你这个矩阵是否存在,唯一,或者不唯一. 题解:这一题就是用传说中的网络流破解.首先建图就是把每一行和每一列看成一个点,行和源点建立一条边,容量为这一行的和,列和汇点建边,容量是这一列的和,然后每一行和每一列建立一边,容量是9.然后跑网络流,如果流量和总和相等,说明有解,然后用判断是否唯一,题解中

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