大意:
原数谜是个很有趣的游戏,如图,每一行或每一列空白称为一个回,每一回都对应着一个整数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;
}