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(脑洞大开的网络流)的更多相关文章

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

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

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

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

  3. HDU 3338 Kakuro Extension

    网络最大流 TLE了两天的题目.80次Submit才AC,发现是刘汝佳白书的Dinic代码还可以优化.....瞬间无语..... #include<cstdio> #include< ...

  4. hdu 3338 最大流 ****

    题意: 黑格子右上代表该行的和,左下代表该列下的和 链接:点我 这题可以用网络流做.以空白格为节点,假设流是从左流入,从上流出的,流入的容量为行和,流出来容量为列和,其余容量不变.求满足的最大流.由于 ...

  5. HDU3338:Kakuro Extension(最大流)

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

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

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

  7. Kakuro Extension HDU - 3338 (Dinic)

    Kakuro puzzle is played on a grid of "black" and "white" cells. Apart from the t ...

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

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

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

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

随机推荐

  1. [AC自己主动机] zoj Searching the String

    意甲冠军: 到原始字符串.给n字符串,每个字符串都有一个属性,属性0代表重叠,1代表不能重叠 请各多少次出现的字符串 思维: 为了便于建立两台机器自己主动(0一个.1一个) 然后,它可以重叠非常好做, ...

  2. Python 实现 淘宝秒杀 聚划算 自己主动提醒 源代码

    说明 本实施例可以监视一起购买的成本button,当警报济济一堂花费时间整点到达(音频文件自定义位置)而自己主动跳出页面(URL习惯). 同一时候还能够通过命令行參数自己定义刷新间隔时间(默认0.1s ...

  3. 一个JSP结果页面tomcat内存溢出

    如今,试验组的同事寻找新能源我看到一个奇怪的现象.一个tomcat应用,内只有一个简单的jsp页面,和这个jsp无论是什么页java代码(我想用这个jsp在她的网页测试server一对tomcat的最 ...

  4. MySql 5.7 重置root密码

    一.以安全模式登录 # Stop MySQL sudo service mysql stop # Make MySQL service directory. sudo mkdir -p /var/ru ...

  5. Linux之tail命令实时收集[纠正误解]

    tail [OPTION]... [FILE]... -c, --bytes=K            output the last K bytes; alternatively, use -c + ...

  6. IdentityServer学习目录

    IdentityServer IdentityServer的基本概念与特性 IdentityServer流程图与相关术语 最简单的IdentityServer实现 最简单的IdentityServer ...

  7. JAVASCRIPT高程笔记-------第 七章 函数表达式

    7.1递归 经典递归例子 function factorial(num){ if(num <= 1){ return 1; }else{ return num * factorial(num - ...

  8. Linux参数调优

    一.系统参数调优 打开文件 /etc/sysctl.conf ############ # 一般服务器调整 # ############ #最大连接数 net.core.somaxconn = 327 ...

  9. UWP入门(八)--几个简单的控件

    原文:UWP入门(八)--几个简单的控件 每天看几个,要不聊几天我就可以看完啦,加油! 看效果 1. CheckBox <TextBlock Grid.Row="0" Tex ...

  10. QML于C++交互之信号与槽(signal&slot )

    connect c++ SIGNAL with QML SLOT 简介 QML 与 C++ 混合编程时,总结了一下qml和c++互相直接调用.及信号与槽连接 的几种情况,详细使用情况看示例代码 所有的 ...