大意:
原数谜是个很有趣的游戏,如图,每一行或每一列空白称为一个回,每一回都对应着一个整数sum,sum就是这回的和。这些空白格里只能填入1—9这九个数字,且在每一回中不能重复。全黑色的格为空,有数字的格,左下角的表示列的和,右上角的表示行的和,则可以得到下面这个图。
但这道题不是原来的数谜,这题与原数谜相比,少了一点规则,就是,每一回中出现的数字可以重复。给你一个n * m 的图,让你填充一下。
看了这题,没有多少思路,借鉴一下解题报告的思想,这题可以用网络流做。以空白格为节点,假设流是从左流入,从上流出的,流入的容量为行和,流出来容量为列和,其余容量不变。求满足的最大流。由于流量有上下限限制,可以给每个数都减掉1,则填出来的数字范围为0—8, 就可以用单纯的网络流搞定了。求出来再加上就可以了。
建图:
一共有四类点:
1. 构造源点S,汇点T
2. 有行和的格子,此类节点设为A
3. 空白格,设为B
4. 有列和的格子,设为C
则可以建边:
1. <S, A> 容量和行和
2. <A, B> 容量为8
3. <B, C> 容量为8
4. <C, T> 容量为列和
当然,反向边容量都置为0。
题目的sample input貌似有错误 我的输出和sample output不一样我调试了好久 不知道哪错了 但是我在网上看了其他人的代码 算出的答案和我一样 我就把我的试着A下结果居然过了 哈哈
#include<iostream> #include<stdio.h> #include<memory.h> #include<cmath> using namespace std; #define MAXN 50005 #define MAXE 1000002 #define INF 0xffffff int ne,nv,tmp,s,t,index; struct Edge{ int next,pair; int v,cap,fLow; }edge[MAXE]; struct gg { int x,y; int val; }row[MAXN],col[MAXN]; int emp,row_num,col_num; int map[102][102]; int net[MAXN]; int ISAP() { int numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN]; int cur_fLow,max_fLow,u,tmp,neck,i; memset(dist,0,sizeof(dist)); memset(numb,0,sizeof(numb)); memset(pre,-1,sizeof(pre)); for(i = 1 ; i <= nv ; ++i) curedge[i] = net[i]; numb[nv] = nv; max_fLow = 0; u = s; while(dist[s] < nv) { if(u == t) { cur_fLow = INF; for(i = s; i != t;i = edge[curedge[i]].v) { if(cur_fLow > edge[curedge[i]].cap) { neck = i; cur_fLow = edge[curedge[i]].cap; } } for(i = s; i != t; i = edge[curedge[i]].v) { tmp = curedge[i]; edge[tmp].cap -= cur_fLow; edge[tmp].fLow += cur_fLow; tmp = edge[tmp].pair; edge[tmp].cap += cur_fLow; edge[tmp].fLow -= cur_fLow; } max_fLow += cur_fLow; u = neck; } /* if .... eLse ... */ for(i = curedge[u]; i != -1; i = edge[i].next) if(edge[i].cap > 0 && dist[u] == dist[edge[i].v]+1) break; if(i != -1) { curedge[u] = i; pre[edge[i].v] = u; u = edge[i].v; }else{ if(0 == --numb[dist[u]]) break; curedge[u] = net[u]; for(tmp = nv,i = net[u]; i != -1; i = edge[i].next) if(edge[i].cap > 0) tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v]; dist[u] = tmp + 1; ++numb[dist[u]]; if(u != s) u = pre[u]; } } return max_fLow; } void addedge(int u,int v,int f) { edge[index].next = net[u]; edge[index].v = v; edge[index].cap = f; edge[index].fLow = 0; edge[index].pair = index+1; net[u] = index++; edge[index].next = net[v]; edge[index].v = u; edge[index].cap = 0; edge[index].fLow = 0; edge[index].pair = index-1; net[v] = index++; } int print( int tp ) { int ans = 0; int id = tp + row_num+1; for( int i = net[id] ; i != -1 ; i = edge[i].next ) { int v = edge[i].v; if( v <=row_num+1 ) { ans+= edge[i].cap; break; } } return ans+1; } int main() { int i,j,m,n; char ts[15]; while(scanf("%d%d",&n,&m)!=EOF) { emp=row_num=col_num=0; for(i=0;i<n;i++) for(j=0;j<m;j++) { scanf("%s",ts); if(ts[0]=='.') { map[i][j]=++emp; } else { map[i][j]=-1; if(ts[4]!='X') { int tp=(ts[4]-'0')*100+(ts[5]-'0')*10+ts[6]-'0'; row[++row_num].x=i; row[row_num].y=j; row[row_num].val=tp; } if(ts[0]!= 'X' ) { int tp = (ts[0]-'0')*100+(ts[1]-'0')*10+ts[2]-'0'; col[++col_num].x = i; col[col_num].y = j; col[col_num].val = tp; } } } t=emp+col_num+row_num+2; nv=t;// 有m+2个点 index=0;//index从0开始扫 s = 1; memset(net,-1,sizeof(net)); for(i=1;i<=row_num;i++) { int pos = i; int x = row[i].x; int y = row[i].y; int cnt_len = 0; for( y=y+1; y <m ; y++ ) { if( map[x][y] != -1 ) { cnt_len++; addedge(i+1, row_num+ map[x][y]+1,8); } else break; } addedge(s,pos+1,row[i].val-cnt_len); } for( i = 1 ; i <=col_num ; i++ ) { int pos =i+1+row_num+emp; int x = col[i].x; int y = col[i].y; int cnt_len = 0; for( x=x+1 ; x < n ; x++ ) { if( map[x][y] != -1 ) //为白点 { cnt_len++; addedge(row_num+ map[x][y]+1,pos,8); } else break; } addedge(pos,t,col[i].val-cnt_len); } ISAP(); for(i=0;i<n;i++) { for(j=0;j<m;j++) { if(map[i][j]==-1) printf("_ "); else //输出的时候加上当前边的流就可以了 printf("%d ",print(map[i][j])); } printf("\n"); } } return 0; }