zoukankan      html  css  js  c++  java
  • 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次。

    网络流真是神奇啊!

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <queue>
      5 using namespace std;
      6 #define N 200005
      7 #define M 1000005
      8 #define INF 0x3f3f3f3f
      9 struct Edge {
     10     int u, v, nxt, cap;
     11     Edge () {}
     12     Edge (int u, int v, int nxt, int cap) : u(u), v(v), nxt(nxt), cap(cap) {}
     13 } edge[M];
     14 struct node {
     15     int id, cid, rid, cval, rval, type;
     16 } mp[105][105];
     17 int head[N], tot, cur[N], pre[N], gap[N], dis[N], S, T, cnt[N];
     18 
     19 void Add(int u, int v, int cap) {
     20     edge[tot] = Edge(u, v, head[u], cap); head[u] = tot++;
     21     edge[tot] = Edge(v, u, head[v], 0); head[v] = tot++;
     22 }
     23 
     24 void BFS() {
     25     queue<int> que;
     26     memset(dis, INF, sizeof(dis));
     27     memset(gap, 0, sizeof(gap));
     28     dis[T] = 0; que.push(T);
     29     while(!que.empty()) {
     30         int u = que.front(); que.pop();
     31         for(int i = head[u]; ~i; i = edge[i].nxt) {
     32             int v = edge[i].v;
     33             if(dis[v] == INF) {
     34                 dis[v] = dis[u] + 1;
     35                 gap[dis[v]]++;
     36                 que.push(v);
     37             }
     38         }
     39     }
     40 }
     41 
     42 int ISAP(int n) {
     43     BFS();
     44     memcpy(cur, head, sizeof(cur));
     45     int u = pre[S] = S, ans = 0, i, flow, index;
     46     while(dis[S] < n) {
     47         if(u == T) {
     48             flow = INF;
     49             for(i = S; i != T; i = edge[cur[i]].v)
     50                 if(flow > edge[cur[i]].cap) flow = edge[cur[i]].cap, index = i;
     51             for(i = S; i != T; i = edge[cur[i]].v)
     52                 edge[cur[i]].cap -= flow, edge[cur[i]^1].cap += flow;
     53             u = index; ans += flow;
     54         }
     55         for(i = cur[u]; ~i; i = edge[i].nxt) if(dis[edge[i].v] == dis[u] - 1 && edge[i].cap > 0) break;
     56         if(~i) {
     57             pre[edge[i].v] = u; cur[u] = i; u = edge[i].v;
     58         } else {
     59             int md = n + 1;
     60             if(--gap[dis[u]] == 0) break;
     61             for(i = head[u]; ~i; i = edge[i].nxt)
     62                 if(dis[edge[i].v] < md && edge[i].cap > 0) md = dis[edge[i].v], cur[u] = i;
     63             gap[dis[u] = md + 1]++;
     64             u = pre[u];
     65         }
     66     }
     67     return ans;
     68 }
     69 
     70 int main() {
     71     int n, m;
     72     while(~scanf("%d%d", &n, &m)) {
     73         char s[10]; tot = 0; int rowcnt = 0, colcnt = 0, white = 0;
     74         memset(head, -1, sizeof(head));
     75         memset(cnt, 0, sizeof(cnt));
     76         memset(mp, 0, sizeof(mp));
     77         for(int i = 1; i <= n; i++) {
     78             for(int j = 1; j <= m; j++) {
     79                 scanf("%s", s); int flag = 0, num = 0;
     80                 if(strcmp(s, "XXXXXXX") == 0) continue;
     81                 if(strcmp(s, ".......") == 0) { mp[i][j].type = 1; white++; mp[i][j].id = white; continue; }
     82                 for(int k = 0; k < 3; k++)
     83                     if(s[k] == 'X') { flag = 1; break; }
     84                     else num = num * 10 + s[k] - '0';
     85                 if(!flag) { mp[i][j].cval = num; colcnt++; mp[i][j].cid = colcnt;}
     86                 flag = 0, num = 0;
     87                 for(int k = 4; k < 7; k++)
     88                     if(s[k] == 'X') { flag = 1; break; }
     89                     else num = num * 10 + s[k] - '0';
     90                 if(!flag) { mp[i][j].rval = num; rowcnt++; mp[i][j].rid = rowcnt;}
     91                 mp[i][j].type = 2;
     92             }
     93         }
     94         S = 0; T = white * 2 + rowcnt + colcnt + 1;
     95         for(int i = 1; i <= n; i++) {
     96             for(int j = 1; j <= m; j++) {
     97                 if(mp[i][j].type == 2) {
     98                     if(mp[i][j].cval > 0) { // 如果黑块上列有数字
     99                         int now = mp[i][j].cid;
    100                         for(int k = i + 1; k <= n; k++) { // 搜这一列上白块
    101                             if(mp[k][j].type == 1) {
    102                                 Add(now + white * 2, mp[k][j].id, INF);
    103                                 mp[i][j].cval--; // 对应的列有白块,这个列容量-1
    104                             } else break; // 不是白块就退出
    105                         }
    106                         Add(S, now + white * 2, mp[i][j].cval);
    107                     }
    108                     if(mp[i][j].rval > 0) { // 如果黑块上行有数字
    109                         int now = mp[i][j].rid;
    110                         for(int k = j + 1; k <= m; k++) { // 搜这一行的白块
    111                             if(mp[i][k].type == 1) {
    112                                 Add(mp[i][k].id + white, now + colcnt + white * 2, INF);
    113                                 mp[i][j].rval--; // 对应的行容量-1
    114                             } else break;
    115                         }
    116                         Add(now + colcnt + white * 2, T, mp[i][j].rval);
    117                     }
    118                 } else if(mp[i][j].type == 1) Add(mp[i][j].id, mp[i][j].id + white, 8); // 白块拆点
    119             }
    120         }
    121         int ans = ISAP(T + 1);
    122         for(int u = 1; u <= white; u++) {
    123             for(int i = head[u]; ~i; i = edge[i].nxt) { // 暴力搜拆点的边
    124                 if(edge[i].v == u + white) {
    125                     cnt[u] = 8 - edge[i].cap; // 这条边的流量为 初始cap - 当前cap
    126                 }
    127             }
    128         }
    129         for(int i = 1; i <= n; i++) {
    130             for(int j = 1; j <= m; j++) {
    131                 if(mp[i][j].type == 1) printf("%d", cnt[mp[i][j].id] + 1);
    132                 else putchar('_');
    133                 if(j != m) putchar(' ');
    134                 else putchar('
    ');
    135             }
    136         }
    137     }
    138     return 0;
    139 }
  • 相关阅读:
    如何安装Tomcat服务器
    浅谈数据库中的锁机制
    彻底理解js中this的指向
    Javascript模块化编程的写法
    滚屏加载--无刷新动态加载数据技术的应用
    JavaScript正则表达式
    CSS:水平居中与垂直居中
    Linux常用命令大全
    HTML的元素嵌套规则
    clearfix清除浮动进化史
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6337353.html
Copyright © 2011-2022 走看看