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. StaticResource和DynamicResource

    Resource 资源(Resource)是保存在可执行文件中的一种不可执行数据,用来保存一些可以被重复利用的样式,对象定义以及一些传统的资源如二进制数据,图片等等我们可以在任何元素上定义资源 Sta ...

  2. jquery属性过滤器

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  3. WPF控件的一些特殊应用

    1 checkbox.IsChecked 返回的是bool?类型,需要用bool强转,或者直接和bool类型比较,将发生隐形转换 2 RadioButton有分组属性GroupName

  4. WPF DataGrid支持的列类型

    WPF DataGrid支持下面几种列类型: DataGridTextColumn DataGridCheckBoxColumn DataGridComboBoxColumn DataGridHype ...

  5. 简单说说Delphi中线程的释放

    线程的释放方式有两种:一种是线程在运行完成后自动释放,一种是手动释放. 无论是那种释放,都应该在线程停止后进行释放. 然而线程的停止也有两种情况:一种是不需要设置标志位,直接完成:一种是由于execu ...

  6. 文字滚屏控件(SliderPanel)

    http://www.delphifans.com/infoview/Article_629.html 日期:2005年9月6日 作者:arhaha {==================== 满天星 ...

  7. centos7 防火墙问题

    centos从7开始默认用的是firewalld,这个是基于iptables的,虽然有iptables的核心,但是iptables的服务是没安装的.所以你只要停止firewalld服务即可:sudo ...

  8. comtextMenu 如何正确的响应MouseLeave事件

    今天给菜单加上这个事件,发现弹出菜单后 鼠标怎么动都不会触发 mouseLeave事件 解决方法是 在菜单loaded事件中,利用visualTreeHelper 访问他内部的border控件,把这个 ...

  9. Linux 下蓝牙bluez分析及使用 (1)

    蓝牙耳机的使用 由于Linux下蓝牙使用不及Windows下直观,致使使用时会出现一些小问题.虽然是小问题,但是由于普通的操作都具有顺序性,前面的中断了,后面的哪怕再简单,也无法继续了.正好近期工作与 ...

  10. Delphi 编写ActiveForm窗体工程知识和样例(开发浏览器客户端应用程序)(有详细步骤)

    一.基础知识介绍: 1.ActiveForm的基础知识介绍: 在Delphi中,ActiveForm是封装了Delphi Form的一种ActiveX控件.ActiveForm其实是一种标准的Delp ...