题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3338

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 _

题目翻译:

如果你解决了‎‎这样的‎‎问题,那就忘了它吧。因为您需要使用完全不同的算法来解决以下算法。‎
‎Kakuro谜题在"黑色"和"白色"细胞的网格上播放。除了上行和最左边的完全黑色的列外,网格还有一定数量的白细胞,它们形成"运行"和一定数量的黑色单元格。"运行"是相邻白细胞的垂直或水平最大单行线块。谜题的每一行和一列可以包含多个"运行"。每个白细胞只属于两个运行 - 一个水平和一个垂直运行。每个水平"运行"始终在黑色半单元格中在其左上方有一个数字,并且每个垂直"运行"在紧接它上方的黑色半单元格中始终有一个数字。这些数字位于"黑色"单元格中,称为"线索"。谜题‎

‎的规则很简单:1.在每个"白色"单元格‎
‎2 中放置一个从 1 到 9 的一位数字。对于所有运行,"运行"中所有数字的总和必须与与"run"‎

‎关联的线索匹配 给定网格,您的任务就是找到解决这个谜题的办法。‎
‎第‎‎个样本输入的图片‎
‎第一个样本输出的图片‎

‎输入‎

‎第一行输入包含两个整数 n 和 m (2 = n,m = 100) = 相应的行数和列数。接下来的 n 行中的每行都包含 m 单元格的说明。每个单元格描述是以下 7 个字符字符串之一:...= ‎
‎ ‎
‎"白色"单元格;‎
‎XXXXXXX= "黑色"细胞,没有线索;‎
‎AAA_BBB_"黑色"单元格,有一个或两个线索。AAA 是相应垂直运行的 3 位线索,如果没有关联的垂直运行,则为 XXX。BBB 是相应水平运行的 3 位线索,如果没有关联的水平运行,则为 XXX。‎
‎网格的第一行和第一列将永远不会有任何白单元格。给定的网格将至少有一个"白色"单元格。保证给定的谜题至少有一个解决方案。‎

‎输出‎

‎将 n 行打印到输出中,每行中都有 m 单元格。对于每个"黑色"单元格打印"+"(下划线),每个"白色"单元格打印解决方案中的相应数字。用单个空格分隔单元格,以便每行由 2m-1 个字符组成。如果有许多解决方案,您可以输出其中任何一个解决方案。

类似与扫雷游戏,先给你一个图,有黑和白,黑色的格子里面有两个数值,左边的值是黑格子当前列开始下面的白色格子之和,右边的值则表示当前列开始右边的白色格子之和。求满足所有黑格子的白格子的合理安排。

之后就是怎么建图了。
首先建图里面需要有刘汝佳白书里的无源无汇有容量下界网络的最大流(P366)的知识,可以看一下,估计第一次也不是很懂,看完之后可以再看下面的建图,估计会懂很多。

总的思路是S->带有行值的黑格子->白色格子->带有列值的黑格子->T。

从S到带有行值的黑格子建的边的容量为行值,不过这个行值要处理一下,因为行值的下限为1,我们可以先把它默认为8,最后处理一下就可以了,所以这里行值为行值减去当前行右边的白格子数目。

之后是带有行值的黑格子到白色格子,它们的容量为8,

之后的都跟上面一样。

具体过程参考代码。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 20500;
const int INF = 0x3f3f3f3f;
int n,m;
struct Edge
{int from,to,cap,flow;
};
vector<int> v[maxn];
vector<Edge> e;
int dis[maxn];  //构建层次图
int cur[maxn];
void init(int n){for(int i=0;i<=n;i++)v[i].clear();e.clear();
}
void addedge(int from,int to,int cap)
{e.push_back((Edge){from,to,cap,0});e.push_back((Edge){to,from,0,0});int m=e.size();v[from].push_back(m-2);v[to].push_back(m-1);
}
bool bfs(int s,int t)
{memset(dis,-1,sizeof(dis));queue<int> q;q.push(s);dis[s] = 0;while(!q.empty()){int x=q.front();q.pop();for(int i=0;i<v[x].size();i++){Edge tmp = e[v[x][i]];if(dis[tmp.to]<0 && tmp.cap>tmp.flow)  //第二个条件保证{dis[tmp.to]=dis[x]+1;q.push(tmp.to);}}}if(dis[t]>0)return true;return false;
}
int dfs(int o,int t,int f)
{if(o==t || f==0)  //优化return f;int a = 0,ans=0;for(int &i=cur[o];i<v[o].size();i++) //注意前面 ’&‘,很重要的优化{Edge &tmp = e[v[o][i]];if(dis[tmp.to]==(dis[o]+1) && (a = dfs(tmp.to,t,min(f,tmp.cap-tmp.flow)))>0){tmp.flow+=a;e[v[o][i]^1].flow-=a; //存图方式ans+=a;f-=a;if(f==0)  //注意优化break;}}return ans;  //优化
}
int dinic(int s,int t)
{int ans=0;while(bfs(s,t)){memset(cur,0,sizeof(cur));int tm=dfs(s,t,INF);ans+=tm;}return ans;
}
int map[250][250];
struct Node
{int x,y,z;//分别表示 x 坐标,y 坐标 以及该行(列)白色格子值的和
}row[maxn],col[maxn];
int main()
{while(~scanf("%d%d",&n,&m)){memset(map,-1,sizeof(map));memset(col,0,sizeof(col));memset(row,0,sizeof(row));int cnt=0,row_cnt=0,col_cnt=0;//分别记录白格子的个数,带有行值的黑格子个数,带有列值的黑格子个数 for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){char str[105];scanf("%s",str);if(str[0] == '.') map[i][j] = ++cnt; //存储白格子的个数并且编号 else{map[i][j] = -1;if(str[0] != 'X'){int tmp = (str[0]-'0')*100 + (str[1]-'0')*10 + str[2]-'0';col[++col_cnt].x = i;//存储下带有列值黑格子的坐标和这一列白格子的值之和 col[col_cnt].y = j;col[col_cnt].z = tmp;}if(str[4] != 'X'){int tmp = (str[4]-'0')*100 + (str[5]-'0')*10 + str[6]-'0';row[++row_cnt].x = i;//存储下带有行值黑格子的坐标和这一行白格子的值之和 row[row_cnt].y = j;row[row_cnt].z = tmp;}} }}int start=0,end=col_cnt+cnt+row_cnt+2;//起点和终点 for(int i = 1;i <= row_cnt;i++){int x = row[i].x;int y = row[i].y;int cnt_len = 0;for(int j = y+1;j <= m;j++){ //记录当前行有多少个白色格子 if(map[x][j] != -1){ cnt_len++;addedge(i,row_cnt+map[x][j],8);//白色格子和带有行值的黑格子建边,容量为 8,表示当前这个值的和是由哪几个数字的和得到的。 }else   break;}addedge(start,i,row[i].z-cnt_len);//建边 s 到所有带有行值的黑格子,容量为这一行的值之和//因为是从 0 到 8 ,所以容量要减去白色格子的数量 }for(int i = 1;i <= col_cnt;i++){int x = col[i].x;int y = col[i].y;int cnt_len = 0;for(int j = x+1;j <= n;j++){//记录当前列有多少个白色格子if(map[j][y] != -1){cnt_len++;addedge(row_cnt+map[j][y],row_cnt+cnt+i,8);//白色格子和有列值的黑格子建边,容量为 8,表示当前这个值的和是由哪几个数字的和得到的。 }else    break;}addedge(row_cnt+cnt+i,end,col[i].z-cnt_len);//建边所有带有列值的黑格子到t,容量为这一行的值之和//因为是从 0 到 8 ,所以权值要减去白色格子的数量}int ans=dinic(start,end);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(map[i][j]==-1)printf("_");elseprintf("%d",e[v[map[i][j]+row_cnt][1]].flow+1);printf("%c",j==m?'\n':' ');}}init(end);}return 0;}

hdu3338——建图+最大流相关推荐

  1. 【BZOJ1061】【codevs1803】志愿者招募,神奇建图费用流

    传送门1 传送门2 写在前面:第一次写成功的费用流是个神奇数学建模题-- 思路:摘自http://www.ithao123.cn/content-4207689.html,感觉这个要比列不等式+松弛操 ...

  2. ZZULIOJ 2131 Can Win【思维建图+最大流】

    2131: Can Win Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 479  Solved: 61 SubmitStatusWeb Board ...

  3. HDU3338 (建图原理详解)

    很经典的题,但是看到还是没思路,太蠢了. 注意下面的行列指的是连续空白格子组成的行和列(意思是每行可以分出多个行) 注意到每个空白格子上的数字只会贡献给本列上面的数字和本行左边的数字 所以可以考虑把每 ...

  4. 解题报告:POJ 3281 Dining(最大流 / “三分图”建图)

    B.POJ 3281 DiningDiningDining(最大流/建图模板)[省选/NOI- ] 有 F 种食物和 D 种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一 种食物和一种饮料.现 ...

  5. POJ2195费用流+BFS建图

    题意:       给你一个n*m的地图,上面有w个人,和w个房子,每个人都要进房子,每个房子只能进一个人,问所有人都进房子的路径总和最少是多少? 思路:       比较简单的最大流,直接建立两排, ...

  6. POJ1149 最大流经典建图PIG

    题意:       有一个人,他有m个猪圈,每个猪圈里都有一定数量的猪,但是他没有钥匙,然后依次来了n个顾客,每个顾客都有一些钥匙,还有他要卖猪的数量,每个顾客来的时候主人用顾客的钥匙打开相应的门,可 ...

  7. hdu4560 不错的建图,二分最大流

    题意: 我是歌手 Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Total Subm ...

  8. POJ 2516 -- Minimum Cost (最小费用最大流, 必须分开建图)

    题目链接 Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In ...

  9. POJ 1087 -- A Plug for UNIX(最大流,建图)(文末有极限数据)

    题目链接 Description You are in charge of setting up the press room for the inaugural meeting of the Uni ...

最新文章

  1. torch 判断gpu可用
  2. 为无LIB的DLL制作LIB函数符号输入库zz
  3. Linux笔记-iptables开放指定端口,开放ICMP协议,其他端口禁止访问
  4. 格式化字符串长度 超出指定长度用....代替
  5. 金蝶K3 WISE 12.3版本系统部署指南
  6. 发两本经典的C/C++教材电子版
  7. 盾神与积木游戏 (贪心典例)
  8. 支付系统,支付流程及实现介绍
  9. 计算机网络统考outlook操作视频,网络教育计算机统考Outlook
  10. PHPcurl请求很慢解决办法
  11. 微信内置浏览器无法下载app(Android/ios)软件 微信内下载链接打不开的解决方法
  12. IIS 相关概念(站点、虚拟目录、应用程序池、隔离模式、W3WP.EXE、Web Gargen) 及 IIS 6的ASP.net请求处理过程
  13. idea 公共方法抽取快捷键
  14. 黑客攻防技巧:2分钟入侵网站全程实录(组图)
  15. 在鼠标右键添加“使用WPS打开”
  16. Tier和Layer
  17. smartctl 使用
  18. 京东毫秒级热key探测框架设计与实践,已完美支撑618大促
  19. ST芯片命名规则简介
  20. ABB IRC5 喷涂机器人简单操作

热门文章

  1. 10.CSS 能量球动画特效
  2. redis mysql 原子计数器_使用redis的increment()方法实现计数器功能案例
  3. Fomo3d,Fowh3d,SOON版F3D最新规则!
  4. 【愚公系列】2023年05月 网络安全高级班 071.WEB渗透与安全(文件包含漏洞原理利用防御)
  5. Gretna计算网络指标操作
  6. java通过反射机制测试private构造函数
  7. opc采集数据(DCOM配置没有问题,但是无法建立连接)
  8. asp.net 下载 有些资源如avi在ie中直接打开
  9. 占淘宝,今日无空,留存
  10. 【Android studio】好用的插件推荐