HDU 3338 Kakuro Extension (网络流,最大流)

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 _

Http

HDU:https://vjudge.net/problem/HDU-3338

Source

网络流,最大流

题目大意

这是一个填数的游戏。在棋盘上有若干白格和黑格。现在要在白色的格子中填数1-9,而黑格是对白格中的数作出要求。黑格中有些没有数字,有些有一个数字,有些有两个数字。如果黑格中有形如a\b的形式,说明从这个格子向下直到碰到一个非白格或出界为止,所有白格的和为a,而从这个格子向右直到碰到一个非白格或出界为止,所有白格上的数之和为b。如果黑格中缺了一个,那么就是对这个方向无要求。任意输出一种填数方案。

解决思路

首先要理解题目意思,有些绕口。然后是用比较好的方式读入(我这里是使用两个矩阵,分别存a\b中的a和b,如果是什么都没有的黑格,置为-1,如果黑格的这一半没有,也置为-1,如果是白格,置为0,其他的则是黑格中对应位置的数),强烈建议先把输入调好后再继续。

这题如果不是在做网络流的时候做,很难想到使用网络流。

首先可以知道,所有黑格左边的数之和等于右边的数之和,同时也等于我们要填的白色格子中的数之和。那么我们可以借助这个条件,从源点连边到黑色格子左边有数的,从黑色格子右边有数的连边到汇点。因为有的黑色格子中既有左边的数又有右边的数,所以我们要拆点,拆成一个负责左边(入),一个负责右边(出)。

再就是处理白色格子。首先,这是一个有上下界的网络流最大流(填的数是1-9),我们要把其转换成0-8,那么对应的那一行的和要对应的减去它对应了多少个白色格子个数。对于列也是一样的。比如这一行三个格子对应的和是22,那么就要变成19。所以我们从所有的黑色格子中左边有数的出发,连到它对应到的同一列的所有白色格子,容量为8,再将所有的白色格子连到其对应的行的的黑色格子。注意白色格子不需要拆点。

细节有些多,要慢慢调。可以参考代码。

另:这里使用Dinic实现最大流,可以参考这篇文章

代码

网络流说明:0是源点,[1,n*m]是第一个图,即所有的白格和黑格的左数,[n*m+1,n*m*2]是所有的黑格的右数,n*m*2+1是汇点

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std; const int maxN=101*101*2;
const int maxM=maxN*100*2;
const int inf=2147483647;
//这两个define分别是把(x,y)对应成一维数组中的位置,即对于每一个格子分配的编号,第二个是把一维数组里的编号转换成二维坐标,并输出,这是为了方便调试
#define pos(x,y) ((x-1)*m+(y-1)%m+1)
#define inpos(x) '['<<x/m+(int)(x%m!=0)<<','<<(x-1)%m+1<<']' class Edge
{
public:
int u,v,flow;
}; int n,m;
int cnt;
int Head[maxN];
int Next[maxM];
Edge E[maxM];
int Mat1[101][101];//第一个矩阵,存黑格中的左数
int Mat2[101][101];//第二个矩阵,存黑格中的右数
int Ans[101][101];//答案矩阵
char str[10];
int cur[maxN];
int Q[maxN];
int depth[maxN]; void Add_Edge(int u,int v,int flow);
bool bfs();
int dfs(int u,int flow); int main()
{
while (cin>>n>>m)
{
cnt=-1;//多组数据,首先清空
memset(Head,-1,sizeof(Head));
memset(Mat1,-1,sizeof(Mat1));
memset(Mat2,-1,sizeof(Mat2));
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)//读入,同时预处理出Mat1和Mat2
{
scanf("%s",str);
if ((str[0]!='X')&&(str[0]!='.'))//如果左数存在
Mat1[i][j]=(str[0]-'0')*100+(str[1]-'0')*10+(str[2]-'0')*1;
if ((str[4]!='X')&&(str[4]!='.'))//如果右数存在
Mat2[i][j]=(str[4]-'0')*100+(str[5]-'0')*10+(str[6]-'0')*1;
if (str[0]=='.')//如果为白格
Mat1[i][j]=0;
if (str[4]=='.')//如果为白格
Mat2[i][j]=0;
}
/*
for (int i=1;i<=n;i++)//输出检查
{
for (int j=1;j<=m;j++)
cout<<Mat1[i][j]<<'/'<<Mat2[i][j]<<" ";
cout<<endl;
}
//*/
for (int i=1;i<=n;i++)//网络流建图,首先建的是黑格左数的
for (int j=1;j<=m;j++)
if (Mat1[i][j]>0)//当找到一个黑格左数存在
{
int k=i+1;//要向下扫描所有的白格,k就是横坐标
while ((Mat1[k][j]==0)&&(k<=n))//只要还是白格并且没有超出范围
{
Add_Edge(pos(i,j),pos(k,j),8);//连这个黑格左数和白格
k=k+1;
}
Add_Edge(0,pos(i,j),Mat1[i][j]-(k-i)+1);//连源点和黑格左数,注意容量是黑格左数-对应的白格数量,白格数量可以通过上面的k与i作差求出
}
for (int i=1;i<=n;i++)//然后建的是黑格右数
for (int j=1;j<=m;j++)
if (Mat2[i][j]>0)//当找到一个黑格右数存在
{
int k=j+1;//要向右扫描所有的白格,k为其纵坐标
while ((Mat2[i][k]==0)&&(k<=m))
{
Add_Edge(pos(i,k),pos(i,j)+n*m,8);
k=k+1;
}
Add_Edge(pos(i,j)+n*m,n*m*2+1,(Mat2[i][j]-(k-j)+1));//连接黑色右格与汇点,注意容量同样也是黑格右数-对应的白格数量,同时注意拆点
}
/*
for (int i=0;i<=cnt;i++)
if (E[i].flow>0)
cout<<inpos(E[i].u)<<" -> "<<inpos(E[i].v)<<" "<<E[i].flow<<endl;
//*/
int Tot=0;//求解最大流
while (bfs())
{
for (int i=0;i<=n*m*2+1;i++)
cur[i]=Head[i];
while (int di=dfs(0,inf))
Tot+=di;
}
//cout<<Tot<<endl;
for (int i=Head[0];i!=-1;i=Next[i])//从源点出发,因为0->黑格左数->白格
{
int u=E[i].v;//找到一个黑格左数点
//cout<<inpos(u)<<" "<<E[i].flow<<endl;
for (int j=Head[u];j!=-1;j=Next[j])//再从黑格左数出发,找其所有对应的白格
{
int v=E[j].v;
int x=v/m+(int)(v%m!=0);//将白格的真实横纵坐标求出来
int y=(v-1)%m+1;
if ((v!=0)&&(E[j].flow<=8)&&(Mat1[x][y]==0))
{
//cout<<inpos(v)<<" "<<E[j].flow<<endl;
Ans[x][y]=8-E[j].flow;//得到答案,8减去残量就是流量,也就是这个格上的数
}
}
//cout<<endl;
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
if (Mat1[i][j]!=0)
printf("_ ");
else
printf("%d ",Ans[i][j]+1);//注意这里要+1,因为我们求的流量是[0,8]而实际求的数是[1,9]
printf("\n");
}
}
return 0;
} void Add_Edge(int u,int v,int flow)
{
cnt++;
Next[cnt]=Head[u];
Head[u]=cnt;
E[cnt].u=u;
E[cnt].v=v;
E[cnt].flow=flow; cnt++;
Next[cnt]=Head[v];
Head[v]=cnt;
E[cnt].u=v;
E[cnt].v=u;
E[cnt].flow=0;
return;
} bool bfs()
{
memset(depth,-1,sizeof(depth));
int h=1,t=0;
Q[1]=0;
depth[0]=1;
do
{
t++;
int u=Q[t];
for (int i=Head[u];i!=-1;i=Next[i])
{
int v=E[i].v;
if ((depth[v]==-1)&&(E[i].flow>0))
{
depth[v]=depth[u]+1;
h++;
Q[h]=v;
}
}
}
while (t!=h);
if (depth[n*m*2+1]==-1)
return 0;
return 1;
} int dfs(int u,int flow)
{
if (u==n*m*2+1)
return flow;
for (int &i=cur[u];i!=-1;i=Next[i])
{
int v=E[i].v;
if ((depth[v]==depth[u]+1)&&(E[i].flow>0))
{
int di=dfs(v,min(flow,E[i].flow));
if (di>0)
{
E[i].flow-=di;
E[i^1].flow+=di;
return di;
}
}
}
return 0;
}

HDU 3338 Kakuro Extension (网络流,最大流)的更多相关文章

  1. HDU - 3338 Kakuro Extension (最大流求解方格填数)

    题意:给一个方格,每行每列都有对白色格子中的数之和的要求.每个格子中的数范围在[1,9]中.现在给出了这些要求,求满足条件的解. 分析:本题读入和建图比较恶心... 用网络流求解.建立源点S和汇点T, ...

  2. HDU 3338 Kakuro Extension

    网络最大流 TLE了两天的题目.80次Submit才AC,发现是刘汝佳白书的Dinic代码还可以优化.....瞬间无语..... #include<cstdio> #include< ...

  3. HDU3338:Kakuro Extension(最大流)

    Kakuro Extension Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  4. Kakuro Extension【最大流】

    HDU-3338 这道题真的处理起来好复杂啊,题意就是个简单的方格填数问题,但是每个白点至少放1,那么最后的可能解是怎样的呢?我们是不是要把x轴上的和y轴上的统一起来,然后就是每个点都被对应的x和y匹 ...

  5. hdu 3338 最大流 ****

    题意: 黑格子右上代表该行的和,左下代表该列下的和 链接:点我 这题可以用网络流做.以空白格为节点,假设流是从左流入,从上流出的,流入的容量为行和,流出来容量为列和,其余容量不变.求满足的最大流.由于 ...

  6. HDU3338 Kakuro Extension —— 最大流、方格填数类似数独

    题目链接:https://vjudge.net/problem/HDU-3338 Kakuro Extension Time Limit: 2000/1000 MS (Java/Others)     ...

  7. HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)

    HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...

  8. HDU 3605 Escape (网络流,最大流,位运算压缩)

    HDU 3605 Escape (网络流,最大流,位运算压缩) Description 2012 If this is the end of the world how to do? I do not ...

  9. HDU 4289 Control (网络流,最大流)

    HDU 4289 Control (网络流,最大流) Description You, the head of Department of Security, recently received a ...

随机推荐

  1. WPF 录屏软件研发心得及思路分享(已结束开发)

    最近由于工程需要开始研发基于Windows的自动录屏软件,很多细节很多功能需要处理,毕竟一个完美的录屏软件不是你随随便便就可以写出来的.首先参考了大部分的录屏软件,在研发的过程中遇到了很多的问题:比如 ...

  2. Mvc_model实体数据验证

    MVC提供了很方便的数据验证,只需要在model里加入相关的正则等,那么就会在前台里生成相关的验证脚本.需要引用两个js文件: jquery.validate.min.js jquery.valida ...

  3. React.js 入门与实战之开发适配PC端及移动端新闻头条平台课程上线了

    原文发表于我的技术博客 我在慕课网的「React.js 入门与实战之开发适配PC端及移动端新闻头条平台」课程已经上线了,文章中是目前整个课程的大纲,以后此课程还会保持持续更新,此大纲文档也会保持更新, ...

  4. 6大爱上react 的理由

    本文翻译自:https://blog.syncano.io/reactjs-reasons-why-part-1/ 书写javascript 更加简单 (⚠️js 中混用html 也一直是外界所诟病的 ...

  5. 探索guava(一)——前置条件Preconditions类

    作用 可以简洁的完成参数检验,在进行业务逻辑代码前进行前置判断.并且避免了冗长的if语句.guava将所有检验的API都放置于Preconditions类中. API Preconditions类大致 ...

  6. css - 背景图片充满整个屏幕

    body { /* 加载背景图 */ background: url("../static/images/index/backImg.jpg") no-repeat; /* 背景图 ...

  7. JWT验证

    理解 JSON Web Token(JWT) 验证 JSON Web Token认证的操作指南 在本文中,我们将了解JSON Web Token的全部内容. 我们将从JWT的基本概念开始,然后查看其结 ...

  8. JavaScript 作用域链与闭包

    作用域链 在某个作用域访问某个变量或者函数时,会首先在自己的局部环境作用域中搜寻变量或者函数,如果本地局部环境作用域中有该变量或者函数,则就直接使用找到的这个变量值或者函数:如果本地局部环境作用域中没 ...

  9. @Autowired的使用:推荐对构造函数进行注释

    在编写代码的时候,使用@Autowired注解是,发现IDE报的一个警告,如下: Spring Team recommends "Always use constructor based d ...

  10. Linux:cut命令详解

    cut 文件内容查看 显示行中的指定部分,删除文件中指定字段 显示文件的内容,类似于下的type命令. 说明 该命令有两项功能,其一是用来显示文件的内容,它依次读取由参数file所指明的文件,将它们的 ...