Kakuro Extension
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1093 Accepted Submission(s): 377
Special Judge
Problem Description
If you solved problem like this, forget it.Because you need to use a completely different algorithm
to solve the following one.
Kakuro puzzle is played on a grid of "black" and "white" cells. Apart from the top row and leftmost column which are entirely black, the grid has some amount of white cells which form "runs" and some amount of black cells. "Run" is a vertical or horizontal
maximal one-lined block of adjacent white cells. Each row and column of the puzzle can contain more than one "run". Every white cell belongs to exactly two runs — one horizontal and one vertical run. Each horizontal "run" always has a number in the black half-cell
to its immediate left, and each vertical "run" always has a number in the black half-cell immediately above it. These numbers are located in "black" cells and are called "clues".The rules of the puzzle are simple:
1.place a single digit from 1 to 9 in each "white" cell
2.for all runs, the sum of all digits in a "run" must match the clue associated with the "run"
Given the grid, your task is to find a solution for the puzzle.
Picture of the first sample input Picture of the first sample output
Input
The first line of input contains two integers n and m (2 ≤ n,m ≤ 100) — the number of rows and columns correspondingly. Each of the next n lines contains descriptions of m cells. Each cell description is one of the following 7-character strings:
.......— "white" cell;
XXXXXXX— "black" cell with no clues;
AAA\BBB— "black" cell with one or two clues. AAA is either a 3-digit clue for the corresponding vertical run, or XXX if there is no associated vertical run. BBB is either a 3-digit clue for the corresponding horizontal run, or XXX if there is no associated
horizontal run.
The first row and the first column of the grid will never have any white cells. The given grid will have at least one "white" cell.It is guaranteed that the given puzzle has at least one solution.
Output
Print n lines to the output with m cells in each line. For every "black" cell print ‘_‘ (underscore), for every "white" cell print the corresponding digit from the solution. Delimit cells with a single space, so that each row consists of 2m-1 characters.If
there are many solutions, you may output any of them.
Sample Input
6 6 XXXXXXX XXXXXXX 028\XXX 017\XXX 028\XXX XXXXXXX XXXXXXX 022\022 ....... ....... ....... 010\XXX XXX\034 ....... ....... ....... ....... ....... XXX\014 ....... ....... 016\013 ....... ....... XXX\022 ....... ....... ....... ....... XXXXXXX XXXXXXX XXX\016 ....... ....... XXXXXXX XXXXXXX 5 8 XXXXXXX 001\XXX 020\XXX 027\XXX 021\XXX 028\XXX 014\XXX 024\XXX XXX\035 ....... ....... ....... ....... ....... ....... ....... XXXXXXX 007\034 ....... ....... ....... ....... ....... ....... XXX\043 ....... ....... ....... ....... ....... ....... ....... XXX\030 ....... ....... ....... ....... ....... ....... XXXXXXX
Sample Output
_ _ _ _ _ _ _ _ 5 8 9 _ _ 7 6 9 8 4 _ 6 8 _ 7 6 _ 9 2 7 4 _ _ _ 7 9 _ _ _ _ _ _ _ _ _ _ _ 1 9 9 1 1 8 6 _ _ 1 7 7 9 1 9 _ 1 3 9 9 9 3 9 _ 6 7 2 4 9 2 _
Author
[email protected]
Source
HDOJ Monthly Contest – 2010.03.06
Recommend
lcy | We have carefully selected several similar problems for you: 1569 1565 3416 3081 3277
题意:n*m的黑白格子,填数字,使白色区域的行列值的和等于有值得黑色区域的相对应的值。
思路:网络流,添加超级源点和汇点,源点和每行中有和值的点相连,汇点和每列中有和值的点相连,每行中有和值的点和该行中对应空白格相连,权值为8,同样每列中有和值的点和该列中对应的空白格相连,权值为8。因为数组开大了,memset时超时了,T了两天,简直了。
后来看到网上的建图方法,是把一整行当作一个点,这样建图简单一点,比我的代码要快。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #pragma comment (linker,"/STACK:102400000,102400000") #define maxn 11000 #define MAXN 200005 #define mod 1000000009 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define FRE(i,a,b) for(i = a; i <= b; i++) #define FREE(i,a,b) for(i = a; i >= b; i--) #define FRL(i,a,b) for(i = a; i < b; i++) #define FRLL(i,a,b) for(i = a; i > b; i--) #define mem(t, v) memset ((t) , v, sizeof(t)) #define sf(n) scanf("%d", &n) #define sff(a,b) scanf("%d %d", &a, &b) #define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c) #define pf printf #define DBG pf("Hi\n") typedef long long ll; using namespace std; struct Edge { int u,v,cap,next; }edge[MAXN]; int head[maxn],cur[maxn],level[maxn]; int num,n,m,cnt; int row_sum[101][101],col_sum[101][101];//(i,j)位置的行,列之和 int row_cnt[101],col_cnt[101]; int number_col[101][101]; //行标号 int number_row[101][101]; //列标号 int number_w[101][101]; //空白处标号 int id[101][101]; //相应的边编号,用于最后输出 char str[101][101][8]; void init() { num=0;cnt=1; mem(head,-1); mem(col_sum,0); mem(row_sum,0); mem(col_cnt,0); mem(row_cnt,0); mem(number_col,0); mem(number_row,0); mem(number_w,0); mem(id,0); } void addedge(int u,int v,int w) { edge[num].u=u; edge[num].v=v; edge[num].cap=w; edge[num].next=head[u]; head[u]=num++; edge[num].u=v; edge[num].v=u; edge[num].cap=0; edge[num].next=head[v]; head[v]=num++; } bool bfs(int s,int t) { mem(level,-1); queue<int>Q; Q.push(s); level[s]=0; while (!Q.empty()) { int u=Q.front(); Q.pop(); for (int i=head[u];i+1;i=edge[i].next) { int v=edge[i].v; if (level[v]==-1&&edge[i].cap>0) { level[v]=level[u]+1; Q.push(v); } } } return level[t]!=-1; } int dfs(int u,int t,int f) { if (u==t) return f; for (int &i=cur[u];i+1;i=edge[i].next) { int v=edge[i].v; if (level[v]==level[u]+1&&edge[i].cap>0) { int d=dfs(v,t,min(f,edge[i].cap)); if (d>0) { edge[i].cap-=d; edge[i^1].cap+=d; return d; } } } return 0; } int dinic(int s,int t,int node) { int flow=0; while (bfs(s,t)) { for (int i=0;i<=node;i++) cur[i]=head[i]; int f; while ((f=dfs(s,t,INF))>0) flow+=f; } return flow; } void build() //建图 { int i,j; for (i=0;i<n;i++) { for (j=0;j<m;j++) { scanf("%s",str[i][j]); if (isdigit(str[i][j][0])) { int t=(str[i][j][0]-'0')*100+(str[i][j][1]-'0')*10+str[i][j][2]-'0'; col_sum[i][j]=t; //保存下(i,j)位置表示的该行数字之和 number_col[i][j]=cnt++; //点编号 } if (isdigit(str[i][j][4])) { int t=(str[i][j][4]-'0')*100+(str[i][j][5]-'0')*10+str[i][j][6]-'0'; row_sum[i][j]=t; //保存下(i,j)位置表示的该列数字之和 number_row[i][j]=cnt++; } if (str[i][j][0]=='.') { col_cnt[j]++; //记录第j列空白格的数目 row_cnt[i]++; //记录第i行空白格的数目 number_w[i][j]=cnt++; //给空白格编号 } } } for (i=0;i<n;i++) { for (j=0;j<m;j++) { if (number_row[i][j]!=0) { int all=0,k=j+1; while (k>=0&&k<m&&number_w[i][k]) { all++; id[i][k]=num; //记录边的序号 addedge(number_row[i][j],number_w[i][k],8); //(i,j)位置和这一行后面的空白格连边 k++; } addedge(0,number_row[i][j],row_sum[i][j]-all); } if (number_col[i][j]!=0) { int all=0,k=i+1; while (k>=0&&k<n&&number_w[k][j]) { all++; addedge(number_w[k][j],number_col[i][j],8);//(i,j)位置和这一列下面的空白格连边 k++; } addedge(number_col[i][j],cnt,col_sum[i][j]-all); } } } } int main() { int i,j; while (~scanf("%d%d",&n,&m)) { init(); build(); int x=dinic(0,cnt,cnt+1); for (i=0;i<n;i++) { for (j=0;j<m;j++) { if (id[i][j]) printf("%d",9-edge[id[i][j]].cap); else printf("_"); if (j<m-1) printf(" "); else printf("\n"); } } } return 0; }