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): 579    Accepted Submission(s): 194
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!

题目意思很简单:就是给出一个矩阵的行和和列和,矩阵中的每个元素都是0-9,问原矩阵是否存在,是否唯一;

分析:网络流求解,如果最大流=所有元素的和则有解;利用残留网络判断是否唯一,方法有两种,第一种是深搜看看是否存在正边权的环,至少3个点构成的环,第二种是用矩阵dp,假如某行的i列元素<9,j列元素>0,而另一行的i列元素>0,j列元素<9,那么答案不是唯一的,因为主对角线的 两个元素可以增大1,而副对角线的两个元素可以减小1,可以明显看出有多个答案;

比赛时的程序:

#include"stdio.h"
#include"string.h"
#include"iostream"
#include"map"
#include"string"
#include"queue"
#include"stdlib.h"
#include"math.h"
#define M 1900
#define eps 1e-10
#define inf 100000000
using namespace std;
struct node
{
int u,v,w,next;
}edge[600000];
int t,head[M],row[M],col[M],q[M],dis[M],work[M],use[M];
void init()
{
t=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)
{
edge[t].u=u;
edge[t].v=v;
edge[t].w=w;
edge[t].next=head[u];
head[u]=t++;
edge[t].u=v;
edge[t].v=u;
edge[t].w=0;
edge[t].next=head[v];
head[v]=t++;
}
int bfs(int S,int T)
{
int rear=0;
memset(dis,-1,sizeof(dis));
dis[S]=0;
q[rear++]=S;
for(int i=0;i<rear;i++)
{
for(int j=head[q[i]];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].w&&dis[v]==-1)
{
dis[v]=dis[q[i]]+1;
q[rear++]=v;
if(v==T)
return 1;
}
}
}
return 0;
}
int dfs(int cur,int a,int T)
{
if(cur==T)
return a;
for(int &i=work[cur];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(edge[i].w&&dis[v]==dis[cur]+1)
{
int tt=dfs(v,min(a,edge[i].w),T);
if(tt)
{
edge[i].w-=tt;
edge[i^1].w+=tt;
return tt;
}
} }
return 0;
}
int Dinic(int S,int T)
{
int ans=0;
while(bfs(S,T))
{
memcpy(work,head,sizeof(head));
while(int tt=dfs(S,inf,T))
ans+=tt;
}
return ans;
}
int DFS(int u,int f)
{
use[u]=1;
for(int &i=work[u];i!=-1;i=edge[i].next)//加&和复制的work数组
{
int v=edge[i].v;
if(edge[i].w&&v!=f)
{
if(use[v])
return 1;
if(DFS(v,u))
return 1;
}
}
use[u]=0;
return 0;
}
int judge(int n,int m)
{
memset(use,0,sizeof(use));
memcpy(work,head,sizeof(head));//当初加了个这东西就莫名其妙的过了,并且很省时
for(int i=1;i<=n;i++)
{
if(DFS(i,i))
return 1;
}
return 0;
}
int main()
{
int n,m,i,j,kk=1;
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
int r=0,c=0;
for(i=1;i<=n;i++)
{
scanf("%d",&row[i]);
r+=row[i];
}
for(j=1;j<=m;j++)
{
scanf("%d",&col[j]);
c+=col[j];
}
printf("Case #%d: ",kk++);
if(r!=c)
{
printf("So naive!\n");
continue;
}
int flag=0;
for(i=1;i<=n;i++)
{
if(m*9<row[i])
flag++;
}
for(i=1;i<=m;i++)
{
if(n*9<col[i])
flag++;
}
if(flag)
{
printf("So naive!\n");
continue;
}
init();
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
add(i,n+j,9);
}
}
for(i=1;i<=n;i++)
add(0,i,row[i]);
for(j=1;j<=m;j++)
add(j+n,m+n+1,col[j]);
int ans=Dinic(0,m+n+1);
if(ans<r)
{
printf("So naive!\n");
continue;
}
if(judge(n,m))
{
printf("So young!\n");
continue;
}
printf("So simple!\n");
}
return 0;
}

之后用矩阵dp做的:

#include"stdio.h"
#include"string.h"
#include"iostream"
#include"map"
#include"string"
#include"queue"
#include"stdlib.h"
#include"math.h"
#define M 1900
#define eps 1e-10
#define inf 1000000000
#define mod 2333333
using namespace std;
struct node
{
int u,v,w,next;
}edge[600000];
int t,head[M],work[M],use[M],dis[M],mp[555][555],G[555][555],row[555],col[555];
void init()
{
t=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)
{
edge[t].u=u;
edge[t].v=v;
edge[t].w=w;
edge[t].next=head[u];
head[u]=t++;
edge[t].u=v;
edge[t].v=u;
edge[t].w=0;
edge[t].next=head[v];
head[v]=t++;
}
int bfs(int S,int T)
{
memset(dis,-1,sizeof(dis));
queue<int>q;
dis[S]=0;
q.push(S);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(edge[i].w&&dis[v]==-1)
{
dis[v]=dis[u]+1;
q.push(v);
if(v==T)
return 1;
}
}
}
return 0;
}
int dfs(int cur,int a,int T)
{
if(cur==T)return a;
for(int &i=work[cur];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(edge[i].w&&dis[v]==dis[cur]+1)
{
int tt=dfs(v,min(edge[i].w,a),T);
if(tt)
{
edge[i].w-=tt;
edge[i^1].w+=tt;
return tt;
}
}
}
return 0;
}
int Dinic(int S,int T)
{
int ans=0;
while(bfs(S,T))
{
memcpy(work,head,sizeof(head));
while(int tt=dfs(S,inf,T))
ans+=tt;
}
return ans;
}
int judge(int n,int m)
{
int k=0,i,j;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
G[i][j]=edge[k^1].w;
k+=2;
}
}
memset(mp,0,sizeof(mp));
for(i=1;i<=n;i++)
{
if(row[i]==0||row[i]==9*m)continue;
for(j=1;j<=m;j++)
{
if(col[j]==0||col[j]==9*n)continue;
for(k=j+1;k<=m;k++)
{
int f1=0,f2=0;
if(G[i][j]<9&&G[i][k]>0)
{
if(mp[k][j])
return 1;
f1++;
}
if(G[i][j]>0&&G[i][k]<9)
{
if(mp[j][k])
return 1;
f2++;
}
if(f1)mp[j][k]=1;
if(f2)mp[k][j]=1;
}
}
}
return 0;
}
int main()
{
int T,m,n,kk=1,i,j;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
int r=0;
for(i=1;i<=n;i++)
{
scanf("%d",&row[i]);
r+=row[i];
}
int c=0;
for(j=1;j<=m;j++)
{
scanf("%d",&col[j]);
c+=col[j];
}
printf("Case #%d: ",kk++);
if(c!=r)
{
printf("So naive!\n");
continue;
}
int flag=0;
for(i=1;i<=n;i++)
if(9*m<row[i])
flag++;
for(j=1;j<=m;j++)
if(9*n<col[j])
flag++;
if(flag)
{
printf("So naive!\n");
continue;
}
init();
int st=0;
int sd=n+m+1;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
add(i,j+n,9);
}
}
for(i=1;i<=n;i++)
add(st,i,row[i]);
for(j=1;j<=m;j++)
add(j+n,sd,col[j]);
int ans=Dinic(st,sd);
if(ans!=r)
{
printf("So naive!\n");
continue;
}
if(judge(n,m))
{
printf("So young!\n");
continue;
}
printf("So simple!\n");
}
return 0;
}

hdu4975 网络流解方程组(网络流+dfs判环或矩阵DP)的更多相关文章

  1. Atcoder Grand Contest 032C(欧拉回路,DFS判环)

    #include<bits/stdc++.h>using namespace std;int vis[100007];vector<int>v[100007];vector&l ...

  2. cf1278D——树的性质+并查集+线段树/DFS判环

    昨天晚上本来想认真打一场的,,结果陪女朋友去了.. 回来之后看了看D,感觉有点思路,结果一直到现在才做出来 首先对所有线段按左端点排序,然后用并查集判所有边是否联通,即遍历每条边i,和前一条不覆盖它的 ...

  3. cf374C Inna and Dima dfs判环+求最长链

    题目大意是有一个DIMA四种字母组成的矩阵,要在矩阵中找最长的DIMADIMADIMA……串,连接方式为四方向连接,问最长能找到多少DIMA.字母可以重复访问,如果DIMA串成环,即可以取出无限长的D ...

  4. UVA818-Cutting Chains(二进制枚举+dfs判环)

    Problem UVA818-Cutting Chains Accept:393  Submit:2087 Time Limit: 3000 mSec  Problem Description Wha ...

  5. 洛谷2444(Trie图上dfs判环)

    要点 并没问具体方案,说明很可能不是构造. 思考不断读入这个文本串,然后中间不出现某些文法的串.啊,这就是个自动机. 将不合法串使用ac自动机构成一个Trie图,我们需要的字符串就是在这个自动机上无限 ...

  6. CodeForces-1217D (拓扑排序/dfs 判环)

    题意 https://vjudge.net/problem/CodeForces-1217D 请给一个有向图着色,使得没有一个环只有一个颜色,您需要最小化使用颜色的数量. 思路 因为是有向图,每个环两 ...

  7. 2018 计蒜之道复赛 贝壳找房魔法师顾问(并查集+dfs判环)

    贝壳找房在遥远的传奇境外,找到了一个强大的魔法师顾问.他有 22 串数量相同的法力水晶,每个法力水晶可能有不同的颜色.为了方便起见,可以将每串法力水晶视为一个长度不大于 10^5105,字符集不大于  ...

  8. HDU 5215 Cycle(dfs判环)

    题意 题目链接 \(T\)组数据,给出\(n\)个点\(m\)条边的无向图,问是否存在一个奇环/偶环 Sol 奇环比较好判断吧,直接判是否是二分图就行了.. 偶环看起来很显然就是如果dfs到一个和他颜 ...

  9. BZOJ 1064 假面舞会(NOI2008) DFS判环

    此题,回想Sunshinezff学长给我们出的模拟题,原题啊有木有!!此处吐槽Sunshinezff爷出题不人道!! 不过也感谢Sunshinezff学长的帮助,我才能做出来.. 1064: [Noi ...

随机推荐

  1. SQL Server 自动重建出现碎片的索引

    1.索引碎片的产生? 由于在表里大量的插入.修改.删除操作而使索引页分裂.如果索引有了高的碎片,有两种情况,一种情况是扫描索引需要花费很多的时间,另一种情况是在查询的时候索引根本不使用索引,都会导致性 ...

  2. Windoows窗口程序七

    WM_QUIT--用于结束消息循环处理 wParam - PostQuitMessage函数传递的参数 lParam - 不使用 当GetMessage收到这个消息后,会返回false,结束while ...

  3. 《FPGA全程进阶---实战演练》第三章之接地设计

    信号回路的电位基准点,(直流电源的负极或者零伏点)在单板上可以分为数字地和模拟地.理想的工作地是电路参考点的等电位平面,然而在实际中,工作地被认为信号电流的低阻抗回路和电源的供电回路,这样就会有三个方 ...

  4. JSONObject、JSONArray

    最近两个星期接触最多的就是json和map了. 之前用到的json,就是一个键对应一个值,超级简单的一对一关系.现在用到的json那可以层层嵌套啊,刚开始接触的时候,确实有种崩溃的赶脚,不想去理,取个 ...

  5. nest(inner) class

    嵌套类,摘自: http://www.ntu.edu.sg/home/ehchua/programmin/java/J4a_GUI.html A nested class has these prop ...

  6. db2

    关于3种导入导出操作进行简单的介绍:export:导出数据,支持IXF,DEL或WSFimport:导入数据,可以向表中导入数据,支持上面提到的4种文件类型.    load:导入数据,功能和impo ...

  7. js openwindow

    进入许多网站时,有弹出式小窗口,它们五花八门,使我们捉摸不透下面就来介绍用JS制作9种制作弹出小窗口: 1.最基本的弹出窗口代码         其实代码非常简单:         < SCRI ...

  8. SharePoint 2010 讨论板列表内容的读取细节处理

    list.Folder表示subject,属于特殊列表,使用list.Folder遍历项,而不是使用list.Items;list.Items表示reply;list.Items[0]["P ...

  9. Loadrunner进行md5加密方法

    本文主要介绍使用Loadrunner进行字符串md5加密的方法. 使用Loadrunner进行md5比较简单,首先是加载md5.h头文件,后使用头文件中的加密函数即可. 1. md5.h头文件内容如下 ...

  10. 帝国CMS 列表模板list.var支持程序代码

    1.增加模板时list.var模板需要勾选“使用程序代码”选项.如图: 2.直接添加PHP代码,不需要加<?和?>程序开始和结束标记. 3.字段值数组变量为$r,对应的字段变量为$r[字段 ...