点击打开链接
题意:给定的分别是每行值的和,每列值的和,每个元素的值在0~9之间,问有多少种情况符合条件,多种,一种和不可能分别输出三种情况
思路:刚读完题根本没有思路,看了网上的才知道用网络流,那样的话就好办了,建个源点,与每行建一条流量为行和的边,每一列与汇点建一条流量为列和的边,每行与每列建一条流量为9的边,跑最大流后判断是否满流就行了,但是要怎么判断有没有多组解呢,当残余网络中有环时,我们可以调整这个环来符合条件,将一条边加1,则另一条边可以减去1,所以判断残余网络中有没有大于2的环,并不会......,看大多数题解都是dfs回溯时删边或者删点,并不会,然后我的做法是将可行的边先预处理出来,然后非常暴力的dfs,一不小心400ms过了.......
#include <queue> #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> #include <functional> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=1010; struct edge{ int to,cap,rev; edge(int a,int b,int c){to=a;cap=b;rev=c;} }; vector<edge>G[maxn]; vector<int>G1[maxn]; int level[maxn],iter[maxn],vis[maxn],n,m; void addedge(int from,int to,int cap){ G[from].push_back(edge(to,cap,G[to].size())); G[to].push_back(edge(from,0,G[from].size()-1)); } void add_edge(int from,int to){ G1[from].push_back(to); } void bfs(int s){ memset(level,-1,sizeof(level)); queue<int>que;level[s]=0; que.push(s); while(!que.empty()){ int v=que.front();que.pop(); for(unsigned int i=0;i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&level[e.to]<0){ level[e.to]=level[v]+1; que.push(e.to); } } } } int dfs(int v,int t,int f){ if(v==t) return f; for(int &i=iter[v];i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&level[v]<level[e.to]){ int d=dfs(e.to,t,min(f,e.cap)); if(d>0){ e.cap-=d; G[e.to][e.rev].cap+=d; return d; } } } return 0; } int max_flow(int s,int t){ int flow=0; while(1){ bfs(s); if(level[t]<0) return flow; memset(iter,0,sizeof(iter)); int f; while((f=dfs(s,t,inf))>0) flow+=f; } } bool Judge_dfs(int x,int val){ vis[x]=1; for(unsigned int i=0;i<G1[x].size();i++){ int t=G1[x][i]; if(t==val) continue; if(vis[t]) return 1; if(Judge_dfs(t,x)) return 1; } vis[x]=0; return 0; } bool judge(){ memset(vis,0,sizeof(vis)); for(int i=0;i<=n+m+1;i++){ for(unsigned int j=0;j<G[i].size();j++){ edge &e=G[i][j]; if(e.cap>0) add_edge(i,e.to); } } for(int i=0;i<=n;i++){ if(Judge_dfs(i,-1)) return 1; } return 0; } int main(){ int T,a,b,t=1; scanf("%d",&T); while(T--){ for(int i=0;i<maxn;i++){ G[i].clear(); G1[i].clear(); } scanf("%d%d",&n,&m); int sum=0,sum1=0,sum2=0; for(int i=1;i<=n;i++){ scanf("%d",&a);sum+=a;sum1+=a; addedge(0,i,a); } for(int j=1;j<=m;j++){ scanf("%d",&b);sum2+=b; addedge(j+n,n+m+1,b); } if(sum1!=sum2){ printf("Case #%d: So naive!\n",t++); continue; } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++) addedge(i,j+n,9); } int ans=max_flow(0,n+m+1); if(ans!=sum) printf("Case #%d: So naive!\n",t++); else{ if(judge()) printf("Case #%d: So young!\n",t++); else printf("Case #%d: So simple!\n",t++); } } return 0; }