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 题目大意:填数字,使白色区域的值得和等于有值得黑色区域的相对应的值,用网络流来做 题目思路:增加 ...
随机推荐
- 专访Jeffrey Richter:Windows 8是微软的重中之重
Jeffrey Richter 以其多本 Windows 核心技术的经典著作而闻名,同时,他深入掌握微软的 .NET 等一系列核心技术,他所创办的 Wintellect 公司与微软有密切的合作关系,他 ...
- C# GC Finalizer IDispseable,.Net的垃圾回收机制
1.GC只能回收堆里的托管资源 2.GC 回收,"代"的概念 .net 托管资源分三代,代数越大 资源的生命周期越长. 0 代 和1代的资源比较少可以比较频率的回收, 回收2代以上 ...
- vs2015 cordova环境安装
原文:vs2015 cordova环境安装 1.参照其他高手的来 http://www.songker.com/index.php/post/151.html VS2015安卓开发Apache Cor ...
- [shell]流程控制----case语句
Shell case语句为多选择语句.可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令.case语句格式如下: case 值 in 模式1) command1 command2 ...
- QT的进程与线程(cmd /c的写法)
该文章原创于Qter开源社区(www.qter.org),作者yafeilinux,转载请注明出处! 导语 在前面的几节内容中讲解了Qt网络编程的一些基本内容,这一节来看一下在Qt中进程和线程的基本应 ...
- 基于VUE实现的新闻后台管理系统-三
开始coding啦 ¶分析项目 根据展示效果我们可以分析出,Web页面有两个,一个用于登录,一个用于系统内容控制,我们分别将其命名为Login和Cms,然后进行路由配置. 在src/page下新建Lo ...
- 基于X.509证书和SSL协议的身份认证过程实现(OpenSSL可以自己产生证书,有TCP通过SSL进行实际安全通讯的实际编程代码)good
上周帮一个童鞋做一个数字认证的实验,要求是编程实现一个基于X.509证书认证的过程,唉!可怜我那点薄弱的计算机网络安全的知识啊!只得恶补一下了. 首先来看看什么是X.509.所谓X.509其实是一种非 ...
- C#实现任意源组播与特定源组播
IP组播通信需要一个特殊的组播地址,IP组播地址是一组D类IP地址,范围从224.0.0.0 到 239.255.255.255.其中还有很多地址是为特殊的目的保留的.224.0.0.0到224.0. ...
- 使用C++还是QML(QML容易使用和维护,效果好)
本质上,Qt 是一个C++类库.在引入 QML 以前,所有的开发都是基于 C++ 的,但到了 Qt 5,QML 和 Qt Quick 成为了 Qt 的核心之一,导致很多初学者在犹豫是否还需要学习 C+ ...
- Cloudera Impala需求
Cloudera Impala需求 为了达到预期的效果,Impala依赖于软件.硬件的可用性,以及下面章节描述的配置. 继续阅读: 支持的操作系统 支持的Hadoop发布 Hive Metastore ...