标签:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4975
3 1 1 5 5 2 2 0 10 0 10 2 2 2 2 2 2
Case #1: So simple! Case #2: So naive! Case #3: So young!
题意:
给出每行每列的和,问是否存在这种表格;每一个小格放的数字仅仅能是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; }
hdu 4975 A simple Gaussian elimination problem.(网络流,推断矩阵是否存在)
标签:
原文地址:http://www.cnblogs.com/lcchuguo/p/4502922.html