Kakuro Extension
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1268 Accepted Submission(s): 439
Special Judge
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
.......— "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.
一個數等於若干個數的和,可以看做一條入流分解爲若干條出流,入流量等於總的出流量。每個格子(i,j)可以由行和列兩個座標確定,所以要在建立行的點和列的點,代表i行的點向代表j列的點連接一條邊(容量範圍【1,9】)就是代表(i,j)這個格子。黑格子的總和,可以分表表示爲流入行點的總流量和跟流出列點的總流量和。某些行(列)可能有多個約束總和,我們可以將每個總和都看做單獨一行(列),所以實際的行數和列數並不一定等於原圖的。還要記錄每個格子對應那一條邊,最後流過那條邊的總流量就是要填的數字。
每個格子範圍是[1,9]的流量,這樣的上下界不方便處理,可以統一都減去1變成[0,8]的範圍,最後答案再加回1.這樣就沒有下界需要處理了。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
using namespace std;
const int maxn =20005;
const int inf=0x3f3f3f3f;
struct Edge
{
int v,cap,nxt;
};
int first[maxn],tot;
Edge edge[200*maxn];
int n,m;
int S,T;
void addedge(int u, int v, int cap)
{
edge[tot]=Edge{v,cap,first[u]};
first[u]=tot++;
edge[tot]=Edge{u,0, first[v]};
first[v]=tot++;
}
struct Val{
int fir,sec;
int emp;
};
Val mp[200][200];
int r[200][200],c[200][200],bel[200][200];
int row[10000],col[10000];
Val turn(char s[8])
{
Val ret;
if(s[0]=='X' || s[0]=='.') ret.fir=-1;
else{
int tmp=0;
for(int i=0; i<3; i++){
tmp=tmp*10+s[i]-'0';
}
ret.fir=tmp;
}
if(s[4]=='X'||s[4]=='.') ret.sec=-1;
else{
int tmp=0;
for(int i=0; i<3; i++){
tmp=tmp*10+s[i+4]-'0';
}
ret.sec=tmp;
}
ret.emp= (s[0]=='.'&&s[4]=='.');
return ret;
}
void init()
{
tot=0;
memset(first, -1, sizeof(first));
char s[8];
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
scanf("%s", s);
mp[i][j]=turn(s);
}
}
S=0,T=n*m+1;
int rowc=1,colc=1;
int cnt=1;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
Val cur=mp[i][j];
if(cur.emp){
continue;
}
if(cur.sec!=-1){
int ed=j+1;
while(ed<=m && mp[i][ed].emp) r[i][ed]=rowc,ed++;
row[rowc]=cnt++;
addedge(0, row[rowc++], cur.sec-(ed-j-1));
}
if(cur.fir!=-1){
int ed=i+1;
while(ed<=n && mp[ed][j].emp) c[ed][j]=colc,ed++;
col[colc]=cnt++;
addedge(col[colc++], T, cur.fir-(ed-i-1));
}
}
}
memset(bel, -1, sizeof(bel));
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++)
if(mp[i][j].emp){
addedge(row[r[i][j]], col[c[i][j]], 8);
bel[i][j]=tot-2;
}
}
}
int d[maxn];
int que[maxn*100], head,tail;
void bfs(int s)
{
memset(d, inf, sizeof(d));
d[s]=0;
head=0;tail=-1;
que[++tail]=s;
while(tail+1!=head){
int u=que[head++];
for(int i=first[u]; i!=-1; i=edge[i].nxt){
int v=edge[i].v, c=edge[i].cap;
if(d[v]!=inf || !c) continue;
d[v]=d[u]+1;
que[++tail]=v;
}
}
}
int cur[maxn];
int dfs(int u, int T, int f)
{
if(u==T) return f;
for(int &i=cur[u]; i!=-1; i=edge[i].nxt){
int v=edge[i].v, c=edge[i].cap, r=i^1;
if(d[v]!=d[u]+1 || !c) continue;
int tmp=dfs(v, T, min(c,f));
if(tmp){
edge[i].cap-=tmp;
edge[r].cap+=tmp;
return tmp;
}
}
return 0;
}
int dinic(int S, int T)
{
int ret=0;
while(true){
bfs(S);
if(d[T]==inf) break;
for(int i=0; i<=T; i++) cur[i]=first[i];
int f=inf;
while( (f=dfs(S,T,f))>0) ret+=f;
}
return ret;
}
int ans[maxn][maxn];
int main()
{
int cas=1;
while(cin>>n>>m){
init();
int t=dinic(S, T);
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
int p=n+m+j+(i-1)*m;
if(bel[i][j]==-1){
ans[i][j]=0;
continue;
}
ans[i][j]=9-edge[bel[i][j]].cap;
}
}
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(!ans[i][j])
putchar('_');
else printf("%d", ans[i][j]);
putchar(j==m?'\n':' ');
}
}
}
return 0;
}