Kakuro Extension HDU - 3338(最大流+ISAP)

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 _
题目大意是给出一个数谜,要求竖直方向的白格子数的和等于上方黑格子斜杠左边的数,水平方向的白格子数的和等于左边黑格子斜杠右边的数,白格子内只能填1到9,题目求任意一种填法。
这里将每个白格子视为一个点,每个黑格子“\”左边和右边分别视为一个点,由于每个黑格子里的数和对应白格子的数的和相等,相当于流入这个点的流量和流出的流量相等,对于白格子,由于水平方向和竖直方向都用了一次,所以流入的流量和流出的流量相等,因此可以建图跑最大流。另外要注意的一点是由于白格子内不能填0,即白格子对应的点,流入和流出的流量不能为0,所以这里默认每个白格子至少填1,所以对应的黑格子的数的容量要减去白格子数,而白格子的容量设置为8,最后输出时+1即可。
将“\”左边的数对应的点与源点相连,容量为这个数减去竖直方向对应白格子数。
将“\”右边的数对应的点与汇点相连,容量为这个数减去水平方向对应白格子数。
将白格子与上方和左边的黑格子的点相连,容量为8。
然后跑最大流,这里用dinic好像会超时,所以用了ISAP。

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e5+5;
const int maxm=1e5+5;
int head[maxn],cur[maxn],dep[maxn],ne,pre[maxn],num[maxn],n,m,S,T,maxflow;
int num1,num2,num3;
queue<int> q;
struct edge
{
	int next,to,cost;
}e[maxm*2];
void add(int u,int v,int w)
{
	e[ne].to=v;
	e[ne].cost=w;
	e[ne].next=head[u];
	head[u]=ne++;
	e[ne].to=u;
	e[ne].cost=0;
	e[ne].next=head[v];
	head[v]=ne++;
}
void bfs(int t)
{
	while(!q.empty()) q.pop();
	for(int i=0;i<=num1+num2+T+num3;i++) cur[i]=head[i];
	for(int i=0;i<=num1+num2+T+num3;i++) dep[i]=num1+num2+T+num3+1;
	dep[t]=0;
	q.push(t);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=head[u];i!=-1;i=e[i].next)
		{
			if(dep[e[i].to]==num1+num2+T+num3+1&&e[i^1].cost)
			{
				dep[e[i].to]=dep[u]+1;
				q.push(e[i].to);
			}
		}
	}
}
int addflow(int s,int t)
{
	int ans=INF,u=t;
	while(u!=s)
	{
		ans=min(ans,e[pre[u]].cost);
		u=e[pre[u]^1].to;
	}
	u=t;
	while(u!=s)
	{
		e[pre[u]].cost-=ans;
		e[pre[u]^1].cost+=ans; 
		u=e[pre[u]^1].to;
	}
	return ans;
}
void ISAP(int s,int t)
{
	int u=s;
	bfs(t);
	for(int i=0;i<=num1+num2+T+num3;i++) num[dep[i]]++;
	while(dep[s]<num1+num2+T+num3+1)
	{
		if(u==t) 
		{
			maxflow+=addflow(s,t);
			u=s;
		}
		int flag=0;
		for(int &i=cur[u];i!=-1;i=e[i].next)
		{
			if(dep[u]==dep[e[i].to]+1&&e[i].cost)
			{
				flag=1;
				pre[e[i].to]=i;
				u=e[i].to;
				break;
			}
		}
		if(!flag)
		{
			int minn=num1+num2+T+num3;
			for(int i=head[u];i!=-1;i=e[i].next)
			{
				if(e[i].cost)
				{
					minn=min(minn,dep[e[i].to]);
				}
			}
			if((--num[dep[u]])==0) break;
			dep[u]=minn+1;
			num[dep[u]]++;
			cur[u]=head[u];
			if(u!=s) u=e[pre[u]^1].to;
		}
	}
}
struct node
{
	char a[100];
	int num1,num2;
}no[200][200];
void init()
{
	memset(head,-1,sizeof(head));
	ne=0;
	memset(num,0,sizeof(num));
	maxflow=0;
	num1=0;num2=0;num3=0;
}
int main()
{
	while(~scanf("%d %d",&n,&m))
	{
		init();
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				scanf("%s",no[i][j].a);
			}
		}
		S=0;
		T=1;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(no[i][j].a[3]=='\\')
				{
					if(no[i][j].a[0]!='X')
					{
						num1++;
						int x=i+1,co=0;
						no[i][j].num1=num1;
						int c=(no[i][j].a[0]-'0')*100+(no[i][j].a[1]-'0')*10+(no[i][j].a[2]-'0')*1;
						while(no[x][j].a[0]=='.'&&x<n)
						{
							co++;
							x++;
						}
						add(S,num1+T,c-co);
					}
				}
			}
		}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(no[i][j].a[3]=='\\')
				{
					if(no[i][j].a[4]!='X')
					{
						num2++;
						int y=j+1,co=0;
						no[i][j].num2=num2;
						int c=(no[i][j].a[4]-'0')*100+(no[i][j].a[5]-'0')*10+(no[i][j].a[6]-'0')*1;
						while(no[i][y].a[0]=='.'&&y<m)
						{
							co++;
							y++;
						}
						add(num1+num2+T,T,c-co);
					}
				}
			}
		}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(no[i][j].a[3]=='.')
				{
					int x=i,y=j;
					while(no[x][j].a[0]=='.') x--;
					while(no[i][y].a[0]=='.') y--;
					num3++;
					add(no[x][j].num1+T,num1+num2+T+num3,8);
					add(num1+num2+T+num3,num1+T+no[i][y].num2,8);
				}
			}
		}
		ISAP(S,T);
		int x=0,d[maxn];
		for(int i=num1*2+num2*2;i<ne;i+=4)
		{
			d[++x]=e[i^1].cost;
		}
		x=0;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(no[i][j].a[3]=='.')
				{
					
					printf(" %d",d[++x]+1);
				}
				else
				{
					if(j==0) printf("_");
					else printf(" _");
				}
			}
			puts("");
		}
	}
}

猜你喜欢

转载自blog.csdn.net/zufe_cst/article/details/86525127