HDU 3338:Kakuro Extension(脑洞大开的网络流)
http://acm.hdu.edu.cn/showproblem.php?pid=3338
题意:在一个n*m的地图里面,有黑方块和白方块,黑方块可能是“XXXXXXX”或者“YYY/YYY”,这里的YYY代表可能为数字,如果是在“/”左边出现数字,代表在它下面的该列的白方块的和加起来要等于这个数字,如果是在“/”右边出现数字,代表它右边的该行的白方块的和加起来要等于这个数字。我们要做的就是求出这些白方块上的数字,并按照要求输出。
思路:看完题意一脸懵逼,想了一个下午还是不知道怎么写。无奈只能看下别人的做法。
因为所有的有行数字的黑方块加起来的和等于所有的有列数字的黑方块加起来的和,所以可以把列看作是源点,把行看作是汇点,然后把有关系的白块和他们连接起来,添加一个超级源点S和列的黑方块相连,添加一个超级汇点T和行的黑方块相连,这样就可以建出图了。至于边的容量,因为是带上下限的网络流(下限是1,上限是9),为了变成没有下限的网络流,所以看作容量上下限为(0-8),这样,所以我选择对白块拆点,两点之间的容量是8,然后列的黑方块和第一个点相连,第二个点和行的黑方块相连,容量都设为INF。超级源点S与列的黑方块的容量和行的黑方块与超级汇点T的容量分别为其方块上的值减去它们对应的白方块数(因为白方块的容量-1了)。最后得到的白方块的拆点的边的容量,答案再+1就转化回来了。还有记得数组要开大点。。一开始忘了开大点T了1次。
网络流真是神奇啊!
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define N 200005
#define M 1000005
#define INF 0x3f3f3f3f
struct Edge {
int u, v, nxt, cap;
Edge () {}
Edge (int u, int v, int nxt, int cap) : u(u), v(v), nxt(nxt), cap(cap) {}
} edge[M];
struct node {
int id, cid, rid, cval, rval, type;
} mp[][];
int head[N], tot, cur[N], pre[N], gap[N], dis[N], S, T, cnt[N]; void Add(int u, int v, int cap) {
edge[tot] = Edge(u, v, head[u], cap); head[u] = tot++;
edge[tot] = Edge(v, u, head[v], ); head[v] = tot++;
} void BFS() {
queue<int> que;
memset(dis, INF, sizeof(dis));
memset(gap, , sizeof(gap));
dis[T] = ; que.push(T);
while(!que.empty()) {
int u = que.front(); que.pop();
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if(dis[v] == INF) {
dis[v] = dis[u] + ;
gap[dis[v]]++;
que.push(v);
}
}
}
} int ISAP(int n) {
BFS();
memcpy(cur, head, sizeof(cur));
int u = pre[S] = S, ans = , i, flow, index;
while(dis[S] < n) {
if(u == T) {
flow = INF;
for(i = S; i != T; i = edge[cur[i]].v)
if(flow > edge[cur[i]].cap) flow = edge[cur[i]].cap, index = i;
for(i = S; i != T; i = edge[cur[i]].v)
edge[cur[i]].cap -= flow, edge[cur[i]^].cap += flow;
u = index; ans += flow;
}
for(i = cur[u]; ~i; i = edge[i].nxt) if(dis[edge[i].v] == dis[u] - && edge[i].cap > ) break;
if(~i) {
pre[edge[i].v] = u; cur[u] = i; u = edge[i].v;
} else {
int md = n + ;
if(--gap[dis[u]] == ) break;
for(i = head[u]; ~i; i = edge[i].nxt)
if(dis[edge[i].v] < md && edge[i].cap > ) md = dis[edge[i].v], cur[u] = i;
gap[dis[u] = md + ]++;
u = pre[u];
}
}
return ans;
} int main() {
int n, m;
while(~scanf("%d%d", &n, &m)) {
char s[]; tot = ; int rowcnt = , colcnt = , white = ;
memset(head, -, sizeof(head));
memset(cnt, , sizeof(cnt));
memset(mp, , sizeof(mp));
for(int i = ; i <= n; i++) {
for(int j = ; j <= m; j++) {
scanf("%s", s); int flag = , num = ;
if(strcmp(s, "XXXXXXX") == ) continue;
if(strcmp(s, ".......") == ) { mp[i][j].type = ; white++; mp[i][j].id = white; continue; }
for(int k = ; k < ; k++)
if(s[k] == 'X') { flag = ; break; }
else num = num * + s[k] - '';
if(!flag) { mp[i][j].cval = num; colcnt++; mp[i][j].cid = colcnt;}
flag = , num = ;
for(int k = ; k < ; k++)
if(s[k] == 'X') { flag = ; break; }
else num = num * + s[k] - '';
if(!flag) { mp[i][j].rval = num; rowcnt++; mp[i][j].rid = rowcnt;}
mp[i][j].type = ;
}
}
S = ; T = white * + rowcnt + colcnt + ;
for(int i = ; i <= n; i++) {
for(int j = ; j <= m; j++) {
if(mp[i][j].type == ) {
if(mp[i][j].cval > ) { // 如果黑块上列有数字
int now = mp[i][j].cid;
for(int k = i + ; k <= n; k++) { // 搜这一列上白块
if(mp[k][j].type == ) {
Add(now + white * , mp[k][j].id, INF);
mp[i][j].cval--; // 对应的列有白块,这个列容量-1
} else break; // 不是白块就退出
}
Add(S, now + white * , mp[i][j].cval);
}
if(mp[i][j].rval > ) { // 如果黑块上行有数字
int now = mp[i][j].rid;
for(int k = j + ; k <= m; k++) { // 搜这一行的白块
if(mp[i][k].type == ) {
Add(mp[i][k].id + white, now + colcnt + white * , INF);
mp[i][j].rval--; // 对应的行容量-1
} else break;
}
Add(now + colcnt + white * , T, mp[i][j].rval);
}
} else if(mp[i][j].type == ) Add(mp[i][j].id, mp[i][j].id + white, ); // 白块拆点
}
}
int ans = ISAP(T + );
for(int u = ; u <= white; u++) {
for(int i = head[u]; ~i; i = edge[i].nxt) { // 暴力搜拆点的边
if(edge[i].v == u + white) {
cnt[u] = - edge[i].cap; // 这条边的流量为 初始cap - 当前cap
}
}
}
for(int i = ; i <= n; i++) {
for(int j = ; j <= m; j++) {
if(mp[i][j].type == ) printf("%d", cnt[mp[i][j].id] + );
else putchar('_');
if(j != m) putchar(' ');
else putchar('\n');
}
}
}
return ;
}
HDU 3338:Kakuro Extension(脑洞大开的网络流)的更多相关文章
- HDU 3338 Kakuro Extension (网络流,最大流)
HDU 3338 Kakuro Extension (网络流,最大流) Description If you solved problem like this, forget it.Because y ...
- HDU - 3338 Kakuro Extension (最大流求解方格填数)
题意:给一个方格,每行每列都有对白色格子中的数之和的要求.每个格子中的数范围在[1,9]中.现在给出了这些要求,求满足条件的解. 分析:本题读入和建图比较恶心... 用网络流求解.建立源点S和汇点T, ...
- HDU 3338 Kakuro Extension
网络最大流 TLE了两天的题目.80次Submit才AC,发现是刘汝佳白书的Dinic代码还可以优化.....瞬间无语..... #include<cstdio> #include< ...
- hdu 3338 最大流 ****
题意: 黑格子右上代表该行的和,左下代表该列下的和 链接:点我 这题可以用网络流做.以空白格为节点,假设流是从左流入,从上流出的,流入的容量为行和,流出来容量为列和,其余容量不变.求满足的最大流.由于 ...
- HDU3338:Kakuro Extension(最大流)
Kakuro Extension Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- HDU3338 Kakuro Extension —— 最大流、方格填数类似数独
题目链接:https://vjudge.net/problem/HDU-3338 Kakuro Extension Time Limit: 2000/1000 MS (Java/Others) ...
- Kakuro Extension HDU - 3338 (Dinic)
Kakuro puzzle is played on a grid of "black" and "white" cells. Apart from the t ...
- L - Kakuro Extension - HDU 3338 - (最大流)
题意:有一个填数字的游戏,需要你为白色的块内填一些值,不过不能随意填的,是有一些规则的(废话),在空白的上方和作方给出一些值,如果左下角有值说明下面列的和等于这个值,右上角的值等于这行后面的数的和,如 ...
- 【最大流】【HDU3338】【Kakuro Extension】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3338 题目大意:填数字,使白色区域的值得和等于有值得黑色区域的相对应的值,用网络流来做 题目思路:增加 ...
随机推荐
- Touch panel DTS 分析(MSM8994平台,Atmel 芯片)
Touch panel DTS 分析(MSM8994平台,Atmel 芯片) 在MSM8994平台,Touch panel的DTS写节点/kernel/arch/arm/boot/dts/qcom/m ...
- QuickReport的OnNeedData的触发情况
1.设置QuickReport的DataSet为空.2.在QuickReport的BeforePrint里面将要显示的数据集合初始化,如Query1.First;3.在OnNeedData里面写代码, ...
- 一步一步造个IoC轮子(二),详解泛型工厂
一步一步造个Ioc轮子目录 一步一步造个IoC轮子(一):Ioc是什么 一步一步造个IoC轮子(二):详解泛型工厂 一步一步造个IoC轮子(三):构造基本的IoC容器 详解泛型工厂 既然我说IoC容器 ...
- Activity跳转通过EventBus传值问题
根据阿里发布的Android开发规范:下载地址:https://102.alibaba.com/downloadFile.do?file=1520478361732/Android_v9.pdf Ac ...
- SQLServer2008-2012开启远程连接的配置方法
一.远程连接端口设置(很关键的一步)1.在服务器上打开SQL Server Configuration Manager.选择SQL Server配置管理器->SQL Server 网络配置-&g ...
- SQL 修改主键约束
原文:SQL 修改主键约束 今天在学习数据库的时候遇到一个关于如何修改主键约束的问题,抄录下来以供备用. --修改主键约束用SQL --获取主键约束名字 declare @csname varchar ...
- Advanced Installer 11.9基于IIS打包札记(For MySQL)
原文:Advanced Installer 11.9基于IIS打包札记(For MySQL) Mysql免安装前期部署 下载绿色命令行版本的mysql,将其放入到发布的程序发布包内,执行Update批 ...
- Linux中的进程
进程,线程,程序 通俗的说,进程是程序的一次执行过程,程序是一种静态概念,如果在系统中引入线程,则进程是资源分配单元,线程是系统执行单元.此处不懂应参阅<操作系统> 进程衍生 fork-e ...
- UWP开发-自适应布局
了解css的人知道,对于不同的屏幕尺寸,css使用一种名为媒体查询的东东来适用不同的屏幕尺寸,以提升用户体验.当用户使用PC等大屏幕的设备时,网页将呈现一种布局形式:而当用户使用手机等小屏幕设备时,布 ...
- vim文本编辑器的基本使用方法
前言 命令模式与编辑模式 内置命令 参考资料注明 前言 vi命令是UNIX操作系统和类UNIX操作系统中最通用的全屏幕纯文本编辑器.Linux中的vi编辑器叫vim,它是vi的增强版(vi Impro ...