HDU3338 Kakuro Extension(最大流+思维构图)
这道题一定要写一下,卡了好久。
题意:
有黑白两种方格,最上边一行和最左边一列一定是黑色,然后其余的地方有可能是黑色,有可能是白色,和白色相邻的黑色方格里有数字(1个或2个),
现在要求在白色方格里填1~9中的一个数字,使得一个黑色方格下边的数字 = sigma(该黑色方格下边白色方格数字) 这个sigma不是下边全部的白方格,
而是一直往下走一直走到一个黑方格之前所有的白方格,详情见样例1。相同的,黑方格右上角的数字 = sigma(该黑色方格右边白色方格数字)。
思路:
可以很容易看出,所有白色方格按行相加 == 所有白色方格按列相加 也就是 所有黑色方格右上角数字和 == 所有黑色方格左下角数字和。那么符合网络流,
源点输入的流量==汇点汇入的流量。建立超级源点sp和超级汇点tp,然后进行以下设定:
type = 0,不带数字的黑色方格
type = 1,白色方格
type = 2,带有两个数字的黑色方格(这个要进行拆点,代码里会标记)
type = 3,只有左下角带数字的黑色方格
type = 4,只有右上角带数字的黑色方格
把黑色方格左下角作为源点,白色方格作为中间点,黑色方格右上角作为汇点。(也可以源点汇点交换一下,如下一行的括号)
接下来进行连边 sp -> type2.3 -> type1 -> type2.4 -> tp。(也可以sp -> type2.4 -> type1 -> type2.3 -> tp)
因为白方格要填1~9有下界1和上界9两个界线,不如让填的数减一,最后再加上,就变成了填0~8可以方便的进行最大流操作
sp -> type2.3连边时,边权为左下角的数减去下边白色方格数*1(因为都减1了)
type2.4 -> tp连边时,边权为右上角的数减去右边白色方格数*1
type2.3 -> type1 -> type2.4连边时,边权设为8
然后跑最大流,求答案

#include <bits/stdc++.h>
using namespace std; const int maxn = + ;
const int maxm = 1e6 + ;
const int inf = 0x3f3f3f3f;
int n, m, d[maxn*maxn], sp, tp, maxflow;
int head[maxn*maxn], tot;
struct point{
int top, lft, type;
} mp[maxn][maxn];
struct edge{
int to, w, next;
} ed[maxm];
int num[maxn][maxn], ans[maxn*maxn];
char s[];
inline void add( int u, int v, int w ){
ed[++tot].to = v; ed[tot].w = w; ed[tot].next = head[u]; head[u] = tot;
ed[++tot].to = u; ed[tot].w = ; ed[tot].next = head[v]; head[v] = tot;
} inline void init(){
memset( head, - ,sizeof(head) );
tot = ;
} inline void map_set(){
for( int i=; i<n; i++ )
for( int j=; j<m; j++ ){
int cnt = ;
if( mp[i][j].type== ){
for( int k=j+; k<m && mp[i][k].type==; k++ )
add( num[i][k], num[i][j], ), cnt ++;
add( num[i][j], tp, mp[i][j].top-cnt );
}else if( mp[i][j].type== ){
for( int k=j+; k<m && mp[i][k].type==; k++ )
add( num[i][k], num[i][j], ), cnt ++;
add( num[i][j], tp, mp[i][j].top-cnt );
cnt = ;
for( int k=i+; k<n && mp[k][j].type==; k++ )
add( num[i][j]-, num[k][j], ), cnt ++; //type==2时,让num[i][j]-1代表左下数字的点
add( sp, num[i][j]-, mp[i][j].lft-cnt );
}else if( mp[i][j].type== ){
for( int k=i+; k<n && mp[k][j].type==; k++ )
add( num[i][j], num[k][j], ), cnt ++;
add( sp, num[i][j], mp[i][j].lft-cnt );
}
}
} inline bool bfs(){
memset( d, , sizeof(d) );
queue<int> q;
d[sp] = ;
q.push(sp);
while( !q.empty() ){
int x = q.front();
q.pop();
for( int i=head[x]; i!=-; i=ed[i].next ){
int y = ed[i].to;
if( ed[i].w && !d[y] ){
d[y] = d[x] + ;
q.push(y);
if( y==tp ) return ;
}
}
}
return ;
} inline int min( int a, int b ){
return a<b ? a:b;
} inline int dfs( int x, int flow ){
if( x==tp ) return flow;
int rest = flow, k;
for( int i=head[x]; i!=- && rest; i=ed[i].next ){
int y = ed[i].to;
if( ed[i].w && d[y]==d[x]+ ){
k = dfs( y, min(rest, ed[i].w) );
if(!k) d[y] = ;
ed[i].w -= k;
ed[i^].w += k;
rest -= k;
}
}
return flow - rest;
} inline void dinic(){
int flow = maxflow = ;
while( bfs() ){
while( flow=dfs(sp, inf) ) maxflow += flow; //该题里 maxflow没什么用,可以不求
}
} inline void output(){
memset( ans, , sizeof(ans) ); //ans记录答案
for( int i=head[sp]; i!=-; i=ed[i].next ){ //超级源点sp是虚拟的,正好利用它进行遍历
int u = ed[i].to;
for( int j=head[u]; j!=-; j=ed[j].next )
ans[ed[j].to] = - ed[j].w + ; //最后要加回1(其实这里为什么要减去边权而不直接用边权我不是很懂,求dalao指教)
}
for( int i=; i<n; i++ ){
putchar('_');
for( int j=; j<m; j++ ){
if( mp[i][j].type!= ) printf(" _");
else printf("%2d", ans[num[i][j]]);
}
puts("");
}
} int main(){
// freopen("in.txt", "r", stdin);
while( ~scanf("%d%d", &n, &m) ){
init();
int nump = ;
for( int i=; i<n; i++ )
for( int j=; j<m; j++ ){
scanf("%s", s);
if( s[]=='.' ){
mp[i][j].type = ;
mp[i][j].top = mp[i][j].lft = ;
}else if( s[]=='X' ){
if( s[]=='X' ) mp[i][j].type = ;
else{
mp[i][j].type = ;
mp[i][j].lft = ;
mp[i][j].top = (s[]-'')* + (s[]-'')* + s[]-'';
}
}else{
if( s[]=='X' ){
mp[i][j].type = ;
mp[i][j].lft = (s[]-'')* + (s[]-'')* + s[]-'';
mp[i][j].top = ;
}else{
mp[i][j].type = ;
mp[i][j].lft = (s[]-'')* + (s[]-'')* + s[]-'';
mp[i][j].top = (s[]-'')* + (s[]-'')* + s[]-'';
}
}
if( mp[i][j].type== ) nump += ; //type == 2的时候就是上半部分和左半部分都有数字,那么将其拆点成两个点
else nump ++;
num[i][j] = nump; //将矩阵的二维编码转换成一维,便于进行操作
}
sp = ; tp = nump+;
map_set();
dinic();
output();
} return ;
}
HDU3338 Kakuro Extension(最大流+思维构图)的更多相关文章
- HDU3338 Kakuro Extension —— 最大流、方格填数类似数独
题目链接:https://vjudge.net/problem/HDU-3338 Kakuro Extension Time Limit: 2000/1000 MS (Java/Others) ...
- hdu3338 Kakuro Extension 最大流
If you solved problem like this, forget it.Because you need to use a completely different algorithm ...
- HDU - 3338 Kakuro Extension (最大流求解方格填数)
题意:给一个方格,每行每列都有对白色格子中的数之和的要求.每个格子中的数范围在[1,9]中.现在给出了这些要求,求满足条件的解. 分析:本题读入和建图比较恶心... 用网络流求解.建立源点S和汇点T, ...
- HDU3338:Kakuro Extension(最大流)
Kakuro Extension Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- HDU 3338 Kakuro Extension (网络流,最大流)
HDU 3338 Kakuro Extension (网络流,最大流) Description If you solved problem like this, forget it.Because y ...
- 【最大流】【HDU3338】【Kakuro Extension】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3338 题目大意:填数字,使白色区域的值得和等于有值得黑色区域的相对应的值,用网络流来做 题目思路:增加 ...
- Kakuro Extension【最大流】
HDU-3338 这道题真的处理起来好复杂啊,题意就是个简单的方格填数问题,但是每个白点至少放1,那么最后的可能解是怎样的呢?我们是不是要把x轴上的和y轴上的统一起来,然后就是每个点都被对应的x和y匹 ...
- L - Kakuro Extension - HDU 3338 - (最大流)
题意:有一个填数字的游戏,需要你为白色的块内填一些值,不过不能随意填的,是有一些规则的(废话),在空白的上方和作方给出一些值,如果左下角有值说明下面列的和等于这个值,右上角的值等于这行后面的数的和,如 ...
- poj 1149 PIGS(最大流经典构图)
题目描述:迈克在一个养猪场工作,养猪场里有M 个猪圈,每个猪圈都上了锁.由于迈克没有钥匙,所以他不能打开任何一个猪圈.要买猪的顾客一个接一个来到养猪场,每个顾客有一些猪圈的钥匙,而且他们要买一定数量的 ...
随机推荐
- linux部署go
一.下载tar包并解压 yum -y install wget glibc.i686 #后面一个是依赖包,不安装会报错: /lib/ld-linux.so.2: bad ELF interpreter ...
- Linux 下杀毒软件 clamav 的安装和使用
安装依赖: 1 2 3 yum install -y pcre* zlib zlib-devel libssl-devel libssl yum install -y openssl yum inst ...
- Flume+Kafka+Storm+Redis 大数据在线实时分析
1.实时处理框架 即从上面的架构中我们可以看出,其由下面的几部分构成: Flume集群 Kafka集群 Storm集群 从构建实时处理系统的角度出发,我们需要做的是,如何让数据在各个不同的集群系统之间 ...
- Ladon内网渗透扫描器PowerShell版
程序简介 Ladon一款用于大型网络渗透的多线程插件化综合扫描神器,含端口扫描.服务识别.网络资产.密码爆破.高危漏洞检测以及一键GetShell,支持批量A段/B段/C段以及跨网段扫描,支持URL. ...
- 钉钉的sonar集成通知
代码地址: https://gitee.com/chejiangyi/dingding-sonar 钉钉(dingding)的sonar(代码质量管理工具的)集成通知,非常简单的一个小工具. 钉钉的s ...
- Effective.Java第56-66条(规范相关)
56. 为所有已公开的API元素编写文档注释 要正确地记录API,必须在每个导出的类.接口.构造方法.方法和属性声明之前加上文档注释.如果一个类是可序列化的,还需要记录它的序列化形式. 文档注释在源 ...
- Python 3 + Selenium 3 实现汉堡王客户调查提交
用Python 3 + Selenium 3实现汉堡王客户调查的自动填写,可以用来作为 python selenium的入门学习实现脚本,列举了几个比较不太好弄的知识点. 上代码: from sele ...
- 使用Docker安装mysql,挂载外部配置和数据
.挂载外部配置和数据安装 mkdir /opt mkdir /opt/mysql mkdir /opt/mysql/conf.d mkdir /opt/mysql/data/ 创建my.cnf配置文件 ...
- http://blog.csdn.net/baidu_31657889/article/details/52315902
Java技术——你真的了解String类的intern()方法吗 转载 2016年08月25日 16:30:14 标签: java intern / intern / java 技术 6542 0.引 ...
- Bagging 和RF的区别
跑训练无聊看了看别人的面经,发现自己一时半会答不上来,整理一下. 一.Bagging介绍 先看一个Bagging的一个概念图(图来自https://www.cnblogs.com/nickchen12 ...