A simple Gaussian elimination problem.
TimeLimit: 2000/1000 MS (Java/Others) Memory Limit:65536/65536 K (Java/Others)
Total Submission(s): 1779 Accepted Submission(s): 546
Problem Description
Dragonis 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 sumof each row and column. Since he thought the map will be useless after he gotthe sums, he destroyed the table after that.
However Dragon's mom came back and found what he had done. She would givedragon a feast if Dragon could reconstruct the table, otherwise keep Dragonhungry. Dragon is so young and so simple so that the original numbers in thetable 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 testcases. Following T blocks, each block describes one test case.
There are three lines for each block. The first line contains two integersN(<=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 theoriginal table, just output: "So naive!", else if we can reconstructthe 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的数字,告诉你矩阵每一行每一列的和,问是否可以还原矩阵。若可还原,还原方法是否唯一。
分析:
-
先进行特判,如果所有行的和不等于所有列的和,显然无法还原。然后利用网络流的最大流模型。
-
建立源点S,连入各个行点,权值为该行的数字和
-
建立汇点T,将各个列点连入汇点T,权值为该列的数字和
-
将各个行点连入汇点T,权值为9,表示每一条边上最大可取9.
-
跑一遍Dinic求最大流,如果最大流为满流,说明可以还原,否则表示不可以还原。
-
判断还原方法是否唯一:只要判断残余网络中是否存在有向环即可:
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<=(b);++i)
#define rush() int T;scanf("%d",&T);while(T--)
typedef long long ll;
const int maxn= 505;
const ll mod = 1e9+7;
const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
struct node
{
int u,v,w,next;
}e[maxn*maxn*10];
int r,c,cnt;
int ss,tt;
int sum1,sum2;
int head[maxn*2];
int cur[maxn*2];
int dis[maxn*2];
int vis[maxn*2];
vector<int>vec[maxn*2];
void add(int u,int v,int w)
{
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt++;
}
int bfs()
{
mst(dis,0);
dis[ss]=1;
queue<int >q;
q.push(ss);
while(!q.empty())
{
int u=q.front();
//if(u==tt) return 1; //两种写法,效率待考察
q.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
int w=e[i].w;
if(w&&dis[v]==0)
{
dis[v]=dis[u]+1;
q.push(v);
}
}
}
if(dis[tt]>0) return 1;
return 0;
}
int dfs(int u,int maxflow)
{
if(tt==u) return maxflow;
int ret=0;
for(int &i=cur[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
int w=e[i].w;
if(w&&dis[v]==dis[u]+1)
{
int add=dfs(v,min(maxflow-ret,w));
e[i].w-=add;
e[i^1].w+=add;
ret+=add;
if(ret==maxflow)
return ret;
}
}
return ret;
}
bool DFS_huan(int now,int pre)
{
vis[now]=1;
for(int i=0;i<vec[now].size();i++)
{
int v=vec[now][i];
if(v==pre) continue;
if(vis[v]==1) return 1;
if(DFS_huan(v,now)) return 1;
}
vis[now]=0; //回溯,如果不回溯而是每个点搜的时候都对vis数组清空的话,时间由0ms退化到280ms
return 0;
}
bool judge()
{
for(int i=0;i<=tt;i++)
{
vec[i].clear();
}
mst(vis,0);
for(int i=0;i<cnt;i++)
{
if(e[i].w>0)
{
vec[e[i].u].push_back(e[i].v);
}
}
for(int i=1;i<=r;i++)
{
if(DFS_huan(i,-1))
return 1;
}
return 0;
}
int Dinic()
{
int ans=0;
while(bfs())
{
memcpy(cur,head,sizeof(head)); //用以引用,提高效率,如不加,此题会TLE
ans+=dfs(ss,INF);
}
return ans;
}
int main()
{
int cas=1;
rush()
{
cnt=0;
mst(head,-1);
scanf("%d%d",&r,&c);
ss=r+c+1;
tt=ss+1;
int x;
sum1=sum2=0;
for(int i=1;i<=r;i++)
{
scanf("%d",&x);
add(ss,i,x);
add(i,ss,0);
sum1+=x;
}
for(int i=1;i<=c;i++)
{
scanf("%d",&x);
add(i+r,tt,x);
add(tt,i+r,0);
sum2+=x;
}
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
{
int u=i;
int v=j+r;
add(u,v,9);
add(v,u,0);
}
printf("Case #%d: ",cas++);
if(sum1!=sum2)
{
//printf("1 ");
puts("So naive!");
continue;
}
int ans=Dinic();
if(ans!=sum1)
{
//printf("2 ");
puts("So naive!");
continue;
}
if(judge())
{
puts("So young!");
}
else puts("So simple!");
}
return 0;
}