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. Linux内核分析作业第八周

    进程的切换和系统的一般执行过程 一.进程调度的时机 中断处理过程(包括时钟中断.I/O中断.系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用sch ...

  2. K 班前7次作业成绩汇总

    K 班前7次作业成绩汇总 得分榜 千帆竞发 详细 短学号 名 1 2 3 4 5 6 7 TOTAL 505 基智 4.55 1 -2 0 0 -10 4.37 -2.08 414 圳源 5.43 2 ...

  3. python中的文件读写(open()函数、with open('file_directory','r') as f:、read()函数等)

    python中也有文件读写,通过调用内置的读写函数.可以完成文件的打开/关闭.读.写入.追加等功能. open()函数 open()函数为python中的打开文件函数,使用方式为: f = open( ...

  4. Online Resource Mapping for SDN Network Hypervisors using Machine Learning

    发表时间:2016 一些定义: self-configuring networks: FlowVisor: FlowVisor是建立在OpenFlow之上的网络虚拟化工具,它可以将物理网络划分成多个逻 ...

  5. 使用PHP + Apache访问有错误的php脚本时不报错

    遇到一个问题: 在命令行编辑php脚本后,直接使用php命令行执行该php脚本,如果脚本出现错误,在命令行的情况下会报错,显示错误信息,比如下面的情况. [root@localhost wwwroot ...

  6. Undertow的InMemorySessionManager

    https://github.com/undertow-io/undertow/blob/master/core/src/main/java/io/undertow/server/session/In ...

  7. Eclipse:An internal error occurred during: "Building workspace". GC overhead limit exceeded

    http://blog.csdn.net/shaozhang872196/article/details/18552273 http://www.cnblogs.com/sonofelice/p/52 ...

  8. [转载]SpringMVC的Model参数绑定方式

    SpringMVC的各种参数绑定方式 http://www.cnblogs.com/HD/p/4107674.html springMVC中复杂嵌套对象.List等集合类型数据绑定 http://ww ...

  9. [日常工作]Oracle新增数据文件的小知识点

    1. 表空间是small file tablespace的 然后数据文件长到了32g左右之后无法再次扩充, 应用报错了 为了性能和最快的处理 使用语句 alter tablespace user ad ...

  10. 关于WrapPanel和RadioButton相互配合使用实WrapPanel现动态添加或删除项

    最近在做一个项目的时候,有一个需求就是,通过RadioButton来控制一行内容的显示与不显示,当不显示的时候,下面的项能够占住相应的位置,当增加的时候,又会在原来的位置重新显示,如果使用一般的Gri ...