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 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!

Source

2014 Multi-University Training Contest
10

题意:

给出每行每列的和,问是否存在这种表格;每一个小格放的数字仅仅能是0--9。

官方题解:http://blog.sina.com.cn/s/blog_6bddecdc0102v01l.html

代码例如以下:(套用别人HDU4888的模板)

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
using namespace std;
#define ll __int64
#define eps 1e-8
const ll Mod=(1e9+7);
const int maxn = 510;
const int maxm = 50100;

int n,m,k;
int r[maxn],c[maxn];
int ma[maxn][maxn];

const int maxnode = 10000 + 5;
const int maxedge = 2*1000000 + 5;
const int oo = 1000000000;
int node, src, dest, nedge;
int head[maxnode], point[maxedge], next1[maxedge], flow[maxedge], capa[maxedge];//point[x]==y表示第x条边连接y,head,next为邻接表,flow[x]表示x边的动态值,capa[x]表示x边的初始值
int dist[maxnode], Q[maxnode], work[maxnode];//dist[i]表示i点的等级
void init(int _node, int _src, int _dest) //初始化,node表示点的个数,src表示起点,dest表示终点
{
    node = _node;
    src = _src;
    dest = _dest;
    for (int i = 0; i < node; i++) head[i] = -1;
    nedge = 0;
}
void addedge(int u, int v, int c1, int c2) //添加一条u到v流量为c1,v到u流量为c2的两条边
{
    point[nedge] = v, capa[nedge] = c1, flow[nedge] = 0, next1[nedge] = head[u], head[u] = (nedge++);
    point[nedge] = u, capa[nedge] = c2, flow[nedge] = 0, next1[nedge] = head[v], head[v] = (nedge++);
}
bool dinic_bfs()
{
    memset(dist, 255, sizeof (dist));
    dist[src] = 0;
    int sizeQ = 0;
    Q[sizeQ++] = src;
    for (int cl = 0; cl < sizeQ; cl++)
        for (int k = Q[cl], i = head[k]; i >= 0; i = next1[i])
            if (flow[i] < capa[i] && dist[point[i]] < 0)
            {
                dist[point[i]] = dist[k] + 1;
                Q[sizeQ++] = point[i];
            }
    return dist[dest] >= 0;
}
int dinic_dfs(int x, int exp)
{
    if (x == dest) return exp;
    for (int &i = work[x]; i >= 0; i = next1[i])
    {
        int v = point[i], tmp;
        if (flow[i] < capa[i] && dist[v] == dist[x] + 1 && (tmp = dinic_dfs(v, min(exp, capa[i] - flow[i]))) > 0)
        {
            flow[i] += tmp;
            flow[i^1] -= tmp;
            return tmp;
        }
    }
    return 0;
}
int dinic_flow()
{
    int result = 0;
    while (dinic_bfs())
    {
        for (int i = 0; i < node; i++) work[i] = head[i];
        while (1)
        {
            int delta = dinic_dfs(src, oo);
            if (delta == 0) break;
            result += delta;
        }
    }
    return result;
}
//建图前,执行一遍init();
//加边时,执行addedge(a,b,c,0),表示点a到b流量为c的边建成(注意点序号要从0開始)
//求解最大流执行dinic_flow(),返回值即为答案

bool judge(int sumrow)
{
    int flow = 1,cost = 0;
    for(int i = 1; i <= n; i++)
        for(int j = n+1; j <= n+m; j ++)
            addedge(i,j,k,0);
    flow=dinic_flow();
    if(flow != sumrow)
        return false;
    return true;
}
int main()
{
    //k为能填原图能填的数字的最大值
    int t;
    int cas = 0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        k = 9;//最多能填9
        init(n+m+2,0,n+m+1);
        int flag = 0;
        int sumrow = 0,colrow = 0;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&r[i]);
            addedge(0,i,r[i],0);
            sumrow += r[i];
            if(r[i]<0 || r[i]>m*k)
                flag = 1;
        }
        for(int j = 1; j <= m; j ++)
        {
            scanf("%d",&c[j]);
            addedge(j+n,n+m+1,c[j],0);
            colrow += c[j];
            if(c[j]<0 || c[j]>n*k)
                flag = 1;
        }
        if(sumrow != colrow)
        {
            printf("Case #%d: So naive!\n",++cas);
            continue;
        }
        if(!judge(sumrow))
            flag = 1;
        if(flag == 1)
        {
            printf("Case #%d: So naive!\n",++cas);
            continue;
        }
        memset(ma,-1,sizeof(ma));
        int i,j;
        for(i=1; i<=n; i++)
            if(r[i]==0)
                for(j=1; j<=m; j++)
                    ma[i][j]=0;
        for(j=1; j<=m; j++)
            if(c[j]==0)
                for(i=1; i<=n; i++)
                    ma[i][j]=0;
        int tt=2;
        int sum,num,temp;
        while(tt--)
        {
            for(i=1; i<=n; i++)
            {
                if(r[i]==0)
                {
                    for(j=1; j<=m; j++)
                        if(ma[i][j]==-1)
                            ma[i][j]=0;
                    continue;
                }
                sum=0;
                num=0;
                for(j=1; j<=m; j++)
                {
                    if(ma[i][j]==-1)
                    {
                        num++;
                        temp=j;
                        sum+=min(k,c[j]);
                    }
                }
                if(num==1)
                {
                    ma[i][temp]=r[i];
                    r[i]-=ma[i][temp];
                    c[temp]-=ma[i][temp];
                    continue;
                }
                else if(sum==r[i])
                {
                    for(j=1; j<=m; j++)
                    {
                        if(ma[i][j]==-1)
                        {
                            ma[i][j]=min(k,c[j]);
                            r[i]-=ma[i][j];
                            c[j]-=ma[i][j];
                        }
                    }
                }
            }
            for(j=1; j<=m; j++)
            {
                if(c[j]==0)
                {
                    for(i=1; i<=n; i++)
                        if(ma[i][j]==-1)
                            ma[i][j]=0;
                    continue;
                }
                sum=0;
                num=0;
                for(i=1; i<=n; i++)
                {
                    if(ma[i][j]==-1)
                    {
                        num++;
                        temp=i;
                        sum+=min(k,r[i]);
                    }
                }
                if(num==1)
                {
                    ma[temp][j]=c[j];
                    r[temp]-=ma[temp][j];
                    c[j]-=ma[temp][j];
                    continue;
                }
                else if(sum==c[j])
                {
                    for(i=1; i<=n; i++)
                    {
                        if(ma[i][j]==-1)
                        {
                            ma[i][j]=min(k,r[i]);
                            r[i]-=ma[i][j];
                            c[j]-=ma[i][j];
                        }
                    }
                }
            }
        }
        flag=0;
        for(i=1; i<=n; i++)
            if(r[i]!=0)
            {
                flag=1;
                break;
            }
        for(j=1; j<=m; j++)
            if(c[j]!=0)
            {
                flag=1;
                break;
            }
        if(flag==1)
            printf("Case #%d: So young!\n",++cas);
        else
        {
            printf("Case #%d: So simple!\n",++cas);
            /* for(i=1; i<=n; i++)
             {
                 for(j=1; j<m; j++)
                     printf("%d ",ma[i][j]);
                 printf("%d\n",ma[i][m]);
             }*/
        }
    }
    return 0;
}
时间: 2024-08-28 03:32:08

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

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 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 题意:同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