题意:有n行m列矩阵,给出各行的和、各列的和,矩阵元素需要为0~9,判断无解、唯一解、多解。
题解:网络流+判环。
和hdu4888几乎一模一样,hdu4888题解链接:http://www.cnblogs.com/yuiffy/p/3891639.html
这题的做法就是hdu4888的做法,点上面的链接怒看如何建图,我下面说这题的不同之处。
可以想到,如果选择一条边递归,然后从递归里出来了,说明没找到环,那么走这条边肯定找不到环,以后也不用走了,可以把这条边删了。或者这条边流量为0,也可以删了。
这样的话每条边最多只进一次,O(m)。
其实4888也可以用这种方法,不过4888还要输出结果,所以先记录结果再删。
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
using namespace std;
#define ll long long
#define usll unsigned ll
#define mz(array) memset(array, 0, sizeof(array))
#define minf(array) memset(array, 0x3f, sizeof(array))
#define REP(i,n) for(i=0;i<(n);i++)
#define FOR(i,x,n) for(i=(x);i<=(n);i++)
#define RD(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define WN(x) prllf("%d\n",x);
#define RE freopen("D.in","r",stdin)
#define WE freopen("1biao.out","w",stdout)
#define mp make_pair
#define pb push_back
int ans;
int r[511],co[511];
int k,nr,nc;
int sumr,sumc;
const int maxn=1111;//点数
const int maxm=555555;//边数
const int inf=9;//MAXINT
struct vnode {
int v,next;
int cap;
};
int cnt,head[maxn];
int h[maxn],g[maxn],d[maxn];//g[i]为标号为i的结点个数,h[i]为i结点的标号,d[]当前弧优化,记录当前弧
bool found;
int n,m,st,ed;//n个点m条边
int augc,flow;//augc为增广路容量,flow为最大流
vnode e[maxm];
inline void add(const int &x,const int &y,const int &z) {
e[cnt].v=y;
e[cnt].cap=z;
e[cnt].next=head[x];
head[x]=cnt;
cnt++;
e[cnt].v=x;
e[cnt].cap=0;
e[cnt].next=head[y];
head[y]=cnt;
cnt++;
}
bool walked[maxn];
bool dfs(const int &x,const int &prex) {///深搜判环
int biu=-1;
walked[x]=true;
for (int i=head[x]; i!=-1; i=e[i].next) {
if(e[i].v==prex){
biu=i;
continue;
}
if (e[i].cap>0) {
if(walked[e[i].v]) return true;
if(dfs(e[i].v,x)) return true;
}
if(biu==-1) head[x]=e[i].next;///删边,因为这条边为0或者走了这条边却没发现环
else e[biu].next=e[i].next;
//biu=i;
}
walked[x]=false;
return false;
}
void aug(const int &m) {
int mini,minh=n-1;
int augco=augc;
int &i=d[m];///当前弧优化
if (m==ed) { //如果当前结点为汇点
found=true;
flow+=augc; //增加流量
return;
}
for (; i!=-1; i=e[i].next) { //寻找容许边
//printf("m=%d,i=%d,e[i].v=%d,e[i].cap=%d,e[i].next=%d\n",m,i,e[i].v,e[i].cap,e[i].next);
//getchar();
if (e[i].cap && h[e[i].v]+1==h[m]) { //如果残留容量大于0,如果是容许边
if (e[i].cap < augc) augc=e[i].cap;//如果容许边流量小于当前增广路流量 则更新增广路流量
//d[m]=i; //把i定为当前弧
aug(e[i].v); //递归
if (h[st]>=n) return; //GAP 如果源点距离标号大于n 则停止算法
if (found) break; //如果找到汇点 则退出寻找
augc=augco;//没找到就还原当前的流
}
}
if (!found) { //重标号
for (int i=head[m]; i!=-1; i=e[i].next) //找那个标号,这里不能用d[m]开始,不然会蛋疼
if (e[i].cap && h[e[i].v]<minh) {
minh=h[e[i].v];
mini=i;
}
g[h[m]]--; //GAP 距离为
if (!g[h[m]]) h[st]=n; //GAP
h[m]=minh+1;
d[m]=mini;
g[h[m]]++; //GAP
} else {
//修改残量
e[i].cap-=augc;
e[i^1].cap+=augc;
}
}
inline void farm() {
int i,j,x,y,z;
memset(head,-1,sizeof(head));
cnt=0;
n=nc+nr+2;
st=n-1;
ed=n;
for(i=1; i<=nc; i++)
add(st,i,co[i]);
for(i=1; i<=nr; i++)
add(nc+i,ed,r[i]);
for(i=1; i<=nc; i++)
for(j=1; j<=nr; j++)
add(i,j+nc,k);
memset(h,0,sizeof(h));
memset(g,0,sizeof(g));
g[0]=n;
flow=0;
for(i=1; i<=n; i++)
d[i]=head[i];//当前弧初始化
while(h[st]<n) {
augc=inf;//初始化增广路容量为正无穷大
found=false;
aug(st);//从源点开始找
}
if(flow!=sumr) {
ans=0;
return;
}
memset(walked,false,sizeof(walked));
for(i=1; i<=nr; i++) { ///因为建图的特性,有环的话环肯定包含1~nr中的点,也就是表示行的结点
if(dfs(i,-1)) {
ans=2;
return;
}
}
ans=1;
//printf("%d\n",flow);
}
inline void read(int &a) {///读入优化
char ch;
bool flag = false;
a = 0;
while(!((((ch = getchar()) >= '0') && (ch <= '9')) || (ch == '-')));
if(ch != '-') {
a *= 10;
a += ch - '0';
} else {
flag = true;
}
while(((ch = getchar()) >= '0') && (ch <= '9')) {
a *= 10;
a += ch - '0';
}
if(flag) {
a = -a;
}
}
int main() {
//RE;
//WE;
int i,j,cas=1,t;
scanf("%d",&t);
while(t--) {
scanf("%d%d",&nr,&nc);
k=9;
sumr=0;
sumc=0;
for(i=1; i<=nr; i++) {
//scanf("%d",&r[i]);
read(r[i]);
sumr+=r[i];
}
for(i=1; i<=nc; i++) {
//scanf("%d",&co[i]);
read(co[i]);
sumc+=co[i];
}
ans=0;
if(sumr==sumc)farm();
if(ans==0) printf("Case #%d: So naive!\n",cas++);
else if(ans!=1) {
printf("Case #%d: So young!\n",cas++);
} else {
printf("Case #%d: So simple!\n",cas++);
}
}
//cout<<"end";
return 0;
}