题意:原数谜是个很有趣的游戏,每一行或每一列空白称为一个回,每一回都对应着一个整数sum,sum就是这回的和。这些空白格里只能填入1—9这九个数字,且在每一回中不能重复。全黑色的格为空,有数字的格,左下角的表示列的和,右上角的表示行的和。但这道题不是原来的数谜,这题与原数谜相比,少了一点规则,就是,每一回中出现的数字可以重复。给你一个n * m 的图,让你填充一下。
难度:4
题解:这题挺有意思的告诉我们每行每列之和,要我们求每个点的流量。我的建图方法太麻烦了,不过也先介绍一下。就是把空白的每个点,都当成最大流中的一个点。(构成点集E)所有行和构成点集R,所有列和构成点集C。然后建图:S->R->E->C->T.流量分别是,行和-改行和包含的元素数,8,8,列和-该列和包含的元素数为什么容量是8?为什么要减去元素数?因为我们只能用1-9填空,那么每个格子最少有1。为了把有上下限的网络流(容量最少为1,最多为9)转化为一般的网络流,减去元素数之后,我们要用0-8填空就行了。最后求点集E流向R的流量就是(该点要求的数-1)其实有一种更简单的方法,意思差不多。只是不要点集E,直接行和列相连接。Amb大牛用的就是这种方法,代码比我少了2k。。
难度:4
题解:这题挺有意思的告诉我们每行每列之和,要我们求每个点的流量。我的建图方法太麻烦了,不过也先介绍一下。就是把空白的每个点,都当成最大流中的一个点。(构成点集E)所有行和构成点集R,所有列和构成点集C。然后建图:S->R->E->C->T.流量分别是,行和-改行和包含的元素数,8,8,列和-该列和包含的元素数为什么容量是8?为什么要减去元素数?因为我们只能用1-9填空,那么每个格子最少有1。为了把有上下限的网络流(容量最少为1,最多为9)转化为一般的网络流,减去元素数之后,我们要用0-8填空就行了。最后求点集E流向R的流量就是(该点要求的数-1)其实有一种更简单的方法,意思差不多。只是不要点集E,直接行和列相连接。Amb大牛用的就是这种方法,代码比我少了2k。。
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 20500
#define maxm 205000
#define inf 2000000000
using namespace std;
int gap[maxn],dis[maxn],pre[maxn],cur[maxn];
int n,NV,m;
struct Edge {
int v,val;
int next;
Edge(){}
Edge( int V , int NEXT , int W = 0 ):v(V),next(NEXT),val(W){}
}edge[maxm];
int cnt_edge,head[maxn];
void Insert_Edge( int u , int v , int flow = 0 ) {
edge[cnt_edge] = Edge(v,head[u],flow);
head[u] = cnt_edge++;
edge[cnt_edge] = Edge(u,head[v]);
head[v] = cnt_edge++;
}
void Init() {
cnt_edge = 0;
memset(head,-1,sizeof(int)*(NV+1));
}
int Sap( int st, int en )
{
memset(dis,0,sizeof(int)*( NV+1));
memset(gap,0,sizeof(int)*( NV+1));
for( int i = 0 ; i < NV ; i++ )
cur[i] = head[i];
int u = pre[st] = st,maxflow = 0,aug = inf;
gap[0] = NV;
while( dis[st] < NV )
{
loop: for( int &i = cur[u]; i != -1 ; i = edge[i].next ) {
int v =edge[i].v;
if( edge[i].val && dis[u] == dis[v]+1) {
aug = aug < edge[i].val? aug: edge[i].val;
pre[v] = u;
u = v;
if( v == en ) {
maxflow += aug;
for( u = pre[u]; v != st ; v = u,u = pre[u] ) {
edge[cur[u]].val -= aug;
edge[cur[u]^1].val += aug;
}
aug = inf;
}
goto loop;
}
}
int mindis = NV;
for( int i = head[u]; i != -1 ; i = edge[i].next ) {
int v = edge[i].v;
if( edge[i].val && mindis > dis[v] ) {
cur[u] = i;
mindis = dis[v];
}
}
if( --gap[dis[u]] == 0 ) break;
gap[ dis[u] = mindis+1 ]++;
u = pre[u];
}
return maxflow;
}
struct Node {
int x,y,val;
}row[10005],col[10005];
int matrix[105][105];
int cnt_row,cnt_col,cnt_empty;
char cc[15];
void print( int tp ) {
int ans = 0;
int id = tp + cnt_col + cnt_row;
for( int i = head[id] ; i != -1 ; i = edge[i].next ) {
int v = edge[i].v;
if( v < cnt_row ) ans += edge[i].val;
}
printf("%d",ans+1);
}
int main() {
while( scanf("%d%d",&n,&m) != EOF ) {
cnt_row = cnt_col = cnt_empty = 0;
for( int i = 0 ; i < n ; i++ )
for( int j = 0 ; j < m ; j++ ) {
scanf("%s",cc);
if( cc[0] == '.' ) {
matrix[i][j] = cnt_empty++;
} else {
matrix[i][j] = -1;
if( cc[4] != 'X' ) {
int tp = (cc[4]-'0')*100+(cc[5]-'0')*10+cc[6]-'0';
row[cnt_row].x = i;
row[cnt_row].y = j;
row[cnt_row++].val = tp;
}
if( cc[0] != 'X' ) {
int tp = (cc[0]-'0')*100+(cc[1]-'0')*10+cc[2]-'0';
col[cnt_col].x = i;
col[cnt_col].y = j;
col[cnt_col++].val = tp;
}
}
}
NV = cnt_col + cnt_row + 2 + cnt_empty;
Init();
int st = NV - 2;
int en = NV - 1;
for( int i = 0 ; i < cnt_row ; i++ ) {
int pos = i;
int x = row[i].x;
int y = row[i].y;
int cnt_len = 0;
for( y++ ; y < m ; y++ ) {
if( matrix[x][y] != -1 ) {
cnt_len++;
Insert_Edge(i, cnt_row + cnt_col + matrix[x][y],8);
} else break;
}
Insert_Edge(st,pos,row[i].val-cnt_len);
}
for( int i = 0 ; i < cnt_col ; i++ ) {
int pos = cnt_row+i;
int x = col[i].x;
int y = col[i].y;
int cnt_len = 0;
for( x++ ; x < n ; x++ ) {
if( matrix[x][y] != -1 ) {
cnt_len++;
Insert_Edge(cnt_row+cnt_col+matrix[x][y],pos,8);
} else break;
}
Insert_Edge(pos,en,col[i].val-cnt_len);
}
Sap(st,en);
for( int i = 0 ; i < n ; i++ ) {
for( int j = 0 ; j < m ; j++ ) {
if( matrix[i][j] == -1 ) printf("_");
else print( matrix[i][j] );
if( j != m -1 ) printf(" ");
}
puts("");
}
}
return 0;
}