这道题一定要写一下,卡了好久。

题意:

有黑白两种方格,最上边一行和最左边一列一定是黑色,然后其余的地方有可能是黑色,有可能是白色,和白色相邻的黑色方格里有数字(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(最大流+思维构图)的更多相关文章

  1. HDU3338 Kakuro Extension —— 最大流、方格填数类似数独

    题目链接:https://vjudge.net/problem/HDU-3338 Kakuro Extension Time Limit: 2000/1000 MS (Java/Others)     ...

  2. hdu3338 Kakuro Extension 最大流

    If you solved problem like this, forget it.Because you need to use a completely different algorithm ...

  3. HDU - 3338 Kakuro Extension (最大流求解方格填数)

    题意:给一个方格,每行每列都有对白色格子中的数之和的要求.每个格子中的数范围在[1,9]中.现在给出了这些要求,求满足条件的解. 分析:本题读入和建图比较恶心... 用网络流求解.建立源点S和汇点T, ...

  4. HDU3338:Kakuro Extension(最大流)

    Kakuro Extension Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  5. HDU 3338 Kakuro Extension (网络流,最大流)

    HDU 3338 Kakuro Extension (网络流,最大流) Description If you solved problem like this, forget it.Because y ...

  6. 【最大流】【HDU3338】【Kakuro Extension】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3338 题目大意:填数字,使白色区域的值得和等于有值得黑色区域的相对应的值,用网络流来做 题目思路:增加 ...

  7. Kakuro Extension【最大流】

    HDU-3338 这道题真的处理起来好复杂啊,题意就是个简单的方格填数问题,但是每个白点至少放1,那么最后的可能解是怎样的呢?我们是不是要把x轴上的和y轴上的统一起来,然后就是每个点都被对应的x和y匹 ...

  8. L - Kakuro Extension - HDU 3338 - (最大流)

    题意:有一个填数字的游戏,需要你为白色的块内填一些值,不过不能随意填的,是有一些规则的(废话),在空白的上方和作方给出一些值,如果左下角有值说明下面列的和等于这个值,右上角的值等于这行后面的数的和,如 ...

  9. poj 1149 PIGS(最大流经典构图)

    题目描述:迈克在一个养猪场工作,养猪场里有M 个猪圈,每个猪圈都上了锁.由于迈克没有钥匙,所以他不能打开任何一个猪圈.要买猪的顾客一个接一个来到养猪场,每个顾客有一些猪圈的钥匙,而且他们要买一定数量的 ...

随机推荐

  1. jvm参数设置实例

  2. 20189220余超 团队博客——阅读软件app

    项目名称 小说阅读器 项目功能 注册登录 用户信息.用户密码.用户图像修改 书籍分类 书架 书籍搜索(作者名或书籍名) 书籍阅读(仅txt格式,暂不支持PDF等其他格式) 阅读字体.背景颜色.翻页效果 ...

  3. BuaaRedSun团队博客目录——北航社团项目

    目录 一.Scrum Meeting 1. Alpha 2. Beta 3. Gamma 二.测试报告 三.发布说明 四.技术博客 后端 前端 五.习得的软工原理/方法/技能? Alpha Beta ...

  4. 【Maven插件】exec-maven-plugin

    <plugin> <artifactId>exec-maven-plugin</artifactId> <groupId>org.codehaus.mo ...

  5. 01.普通抖音新手如何从0开始入门3个月做到粉丝100w+

    普通抖音新手如何从0开始入门3个月做到粉丝100w+ 今年以来,明显感觉抖音很火,大有干掉微信,取代淘宝,京东的感觉,如今年轻人,一周7天有7天要玩抖音,所以说未来不可估量. 如是,2019春节以后, ...

  6. mySql使用手册-官方文档

    https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format oracle to_ ...

  7. C语言是什么

    大家对于Java可能并不陌生,那你对c语言了解多少呢,今天小编带大家来了解c语言是什么. c语言是一门面向过程.抽象化的通用程序设计语言,广泛应用于底层开发.C语言具有高效.灵活.功能丰富.表达力强和 ...

  8. HDU校赛 | 2019 Multi-University Training Contest 2

    2019 Multi-University Training Contest 2 http://acm.hdu.edu.cn/contests/contest_show.php?cid=849 100 ...

  9. Windows定时清理文件处理脚本

    一.运行CMD,输入forfile/?,即可获取forfile的使用方法 /P  路径 /M  文件类型 /D  时间   + | -     +:之后    - :之前   example:-2   ...

  10. CMS-headless or non-headless, page-based or object-based storage?

    内容管理系统对于很多在线教育企业来说都是至关重要的,他不仅可以用于内容的创作,编辑,发布,撤销,展示也可以用于运营或者市场产生他们需要的页面. 传统上,Wordpress是一个非常成功的CMS,他将内 ...