HDU 3338 Kakuro Extension (网络流,最大流)
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 (网络流,最大流)的更多相关文章
- HDU - 3338 Kakuro Extension (最大流求解方格填数)
题意:给一个方格,每行每列都有对白色格子中的数之和的要求.每个格子中的数范围在[1,9]中.现在给出了这些要求,求满足条件的解. 分析:本题读入和建图比较恶心... 用网络流求解.建立源点S和汇点T, ...
- HDU 3338 Kakuro Extension
网络最大流 TLE了两天的题目.80次Submit才AC,发现是刘汝佳白书的Dinic代码还可以优化.....瞬间无语..... #include<cstdio> #include< ...
- HDU3338:Kakuro Extension(最大流)
Kakuro Extension Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- Kakuro Extension【最大流】
HDU-3338 这道题真的处理起来好复杂啊,题意就是个简单的方格填数问题,但是每个白点至少放1,那么最后的可能解是怎样的呢?我们是不是要把x轴上的和y轴上的统一起来,然后就是每个点都被对应的x和y匹 ...
- hdu 3338 最大流 ****
题意: 黑格子右上代表该行的和,左下代表该列下的和 链接:点我 这题可以用网络流做.以空白格为节点,假设流是从左流入,从上流出的,流入的容量为行和,流出来容量为列和,其余容量不变.求满足的最大流.由于 ...
- HDU3338 Kakuro Extension —— 最大流、方格填数类似数独
题目链接:https://vjudge.net/problem/HDU-3338 Kakuro Extension Time Limit: 2000/1000 MS (Java/Others) ...
- HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)
HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...
- HDU 3605 Escape (网络流,最大流,位运算压缩)
HDU 3605 Escape (网络流,最大流,位运算压缩) Description 2012 If this is the end of the world how to do? I do not ...
- HDU 4289 Control (网络流,最大流)
HDU 4289 Control (网络流,最大流) Description You, the head of Department of Security, recently received a ...
随机推荐
- asp.net mvc接收安卓post的json字符串
筛选器: using System; using System.Collections.Generic; using System.Linq; using System.Web; using Syst ...
- linux RPM manager
RPM manage:rpm2cpio package_name | cpio -id #将一个rpm包解压至当前目录rpm -qi package_name #查看一个已安装的rpm包信息rpm - ...
- 本地开发环境搭建(windows)
一.虚拟器安装 1.概念 ・为什么要搭建搭建模拟环境 在租借服务器前用手中的PC模拟一个服务器的环境,可以打包与团队人员分享 ・什么是Vagrant https://segmentfault.com/ ...
- 多校寒训TaoTao要吃鸡dp
题目描述 Taotao的电脑带不动绝地求生,所以taotao只能去玩pc版的荒野行动了, 和绝地求生一样,游戏人物本身可以携带一定重量m的物品,装备背包 之后可以多携带h(h为0代表没有装备背包)重量 ...
- 结对编程 学习手记ver1.2
团队成员: 226 高雅智 164刘浩然: 一 结对编程 辛辛苦苦搞了好久的时间,就是没有人家的快,明明算法都差不多,哎~~~ 结对的优势,在于双方互相督促,对于代码能贡献自己的能力,人多力量 ...
- PairProject——结对编程
成员:12061162 王骜 12061225 钟毅恒 一.合作过程中的照片 . 二.结对编程的优缺点 优点: 1)在编程过程中,任何一段代码都不断地复审,同时避免了将写代码的责任抛给一个人的问题 ...
- 冲刺Two之站立会议9
今天我们团队主要针对软件的功能进行了改进.因为它目前可以实现视频通话,语音聊天,文件传输和文字聊天的通信功能,我们想要在它的基础上实现临时局域群聊和群聊视频的功能,目前还没有完全实现.
- android 活动的生命周期
掌握活动的生命周期非常重要,因为一个正常的android应用,会有很多的活动,如何在这些活动之间进行切换.数据的交互等,就经常会用到活动的生命周期这一块的知识.可以说,只要掌握了活动的生命周期,才能更 ...
- Magazine Ad CodeForces - 803D (二分+贪心)
The main city magazine offers its readers an opportunity to publish their ads. The format of the ad ...
- octave基本指令5
octave基本指令5 控制语句 for >> v=zreos(5,1) v = 0 0 0 0 0 >> for i=1:10, > v(i) = 2^i; > ...