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. Rancher + k8s + docker 部署资料

    一.k8s 文档: https://jimmysong.io/kubernetes-handbook/concepts/deployment.html 命令行大全 https://kubernetes ...

  2. CSS文本实例

    CSS 文本属性可定义文本的外观. 通过文本属性,您可以改变文本的颜色.字符间距,对齐文本,装饰文本,对文本进行缩进,等等.#############################CSS 文本属性属 ...

  3. 总结几个常用的系统安全设置(含DenyHosts)

    1)禁止系统响应任何从外部/内部来的ping请求攻击者一般首先通过ping命令检测此主机或者IP是否处于活动状态如果能够ping通 某个主机或者IP,那么攻击者就认为此系统处于活动状态,继而进行攻击或 ...

  4. Oracle数据库设置为归档模式的操作方法

    Oracle归档模式非常非常重要!对于有些数据库刚装好后可能是非归档模式,这是很危险的!为了安全起见,一定要谨记:对于Oracle数据库,一定要设置为归档模式,尤其是生产库,只有这样才能实现数据库的有 ...

  5. Centos7.5部署MySQL5.7基于GTID主从复制+并行复制+半同步复制+读写分离(ProxySQL) 环境- 运维笔记 (完整版)

    之前已经详细介绍了Mysql基于GTID主从复制的概念,原理和配置,下面整体记录下MySQL5.7基于GTID主从复制+并行复制+增强半同步复制+读写分离环境的实现过程,以便加深对mysql新特性GT ...

  6. Python_试题_23

    # Python基础数据类型考试题# 考试时间:两个半小时 满分100分(80分以上包含80分及格)# 一,基础题.# 1,简述变量命名规范(3分)# 答:变量名是由数字.字母.下划线任意组合,变量名 ...

  7. 《Linux内核设计与实现》课本第四章学习总结

    进程调度 4.1 多任务 多任务操作系统就是能同时并发的交互执行多个进程的操作系统. 多任务系统分为两种: 抢占式多任务:Linux提供了抢占式的多任务模式,由调度程序来决定什么时候停止一个进程的运行 ...

  8. svn 使用教程

    一.什么是SVN SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS.CVS,它采用了分支管理系统,它的设计目标就是取代CVS. 二.SVN的下载安装 下载地址:http ...

  9. SQL Server 递归查询上级或下级组织数据(上下级数据通用查询语法)

    查询上级组织数据: WITH OCTE AS ( AS LVL FROM IOV_Users U LEFT JOIN IOV_Organization O ON U.OrgId=O.ID UNION ...

  10. mybatis分页 -----PageHelper插件

    对查询结果进行分页 一,使用limit进行分页 1.mybatis 的sql语句: <if test="page !=null and rows !=null"> li ...