HDU - 3338 Kakuro Extension(建图 + 最大流)

http://acm.hdu.edu.cn/showproblem.php?pid=3338

题意:

有黑格子和白格子黑格子有数字第一个A意味着向下的白格子的权值和为A, 第二个B意味者向右的权值为B

思路:

咋一看意味是深搜,但数据太大了,结果发现可以用网络流写(其实是看了别人博客-_-),
1。把每个黑格子编号,向下有值的编1 -> rn,向右有值的编rn + 1 -> rn + cn
1。把源点S 与每个向下有值的黑格子相连,汇点T与每个向右有值的黑格子相连。权值都为黑格子的值
2。因为每一个白格子都被用了两次,一次是上方的黑格子用了,一次是左方的黑格子用了,所以黑格子向下的和与向右的权值和相同。(流入流量==流出流量)。
3。把黑格子与它所对应的白格子相连(类似这样)
这里写图片描述
把每条边的权值赋值为8
4。为什么权值是8
先举个栗子:
一张这样的图(忘画T了。。。)
这里写图片描述
跑完最大流后
这里写图片描述
这时1->2是0流,即没有流量流过,而经过这样一个最大流后从S->T最大流把S的流量流完,可以类比到题目

源点S->每个下方有白格子的黑格子->白格子->右方有格子的白格子-> 汇点T

因为可能有0流的存在,所以把黑格子-> 白格子的权值设为8,跑过Dinic后,用9减去每条边的剩余流量就是满足条件流走的最大流,这时,0流减完就为1,这样就不会出现有的白格子里有0的情况,符合题目条件

AC代码

#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <stdio.h>
#include <deque>

using namespace std;

#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define maxn 1000005
#define eps 0.00000001
#define PI acos(-1.0)
#define M 1000000007

struct Edge{
    int v, w, nxt;
}edge[maxn];

struct TU{
    int r, c;
}Tu[105][105];

int head[maxn], dis[maxn], cur[maxn], tot, S, T;
char s[10];
int rec[105][105], row[maxn], col[maxn], rn, cn;
int n, m;

void init() {
    tot = 0;
    memset(head, -1, sizeof(head));
    memset(row, 0, sizeof(row));
    memset(col, 0, sizeof(col));
    memset(rec, -1, sizeof(rec));
    rn = cn = 0;
}

void addEdge(int u, int v, int w) {
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].nxt = head[u];
    head[u] = tot ++;

    edge[tot].v = u;
    edge[tot].w = 0;
    edge[tot].nxt = head[v];
    head[v] = tot ++;
}

bool bfs() {
    memset(dis, -1, sizeof(dis));
    dis[T] = 0;
    queue<int> que;
    que.push(T);
    while(!que.empty()) {
        int u = que.front(); que.pop();
        for (int i = head[u]; i + 1; i = edge[i].nxt) {
            if(dis[edge[i].v] == -1 && edge[i ^ 1].w > 0) {
                dis[edge[i].v] = dis[u] + 1;
                que.push(edge[i].v);
            }
        }
    }
    return dis[S] != -1;
}

int dfs(int u, int flow) {
    if(u == T) return flow;
    int delta = flow;
    for (int &i = cur[u]; i + 1; i = edge[i].nxt) {
        if(dis[u] == dis[edge[i].v] + 1 && edge[i].w > 0) {
            int d = dfs(edge[i].v, min(delta, edge[i].w));
            edge[i].w -= d; edge[i ^ 1].w += d;
            delta -= d;
            if(delta == 0) break;
        }
    }
    return flow - delta;
}

int dinic() {
    int ans = 0;
    while(bfs()) {
        for (int i = 0; i <= T; i ++)
            cur[i] = head[i];
        ans += dfs(S, INF);
    }
    return ans;
}

int GetNum(int l, int r) {
    if(s[l] == 'X') return -1;
    else return 100 * (s[l] - '0') + 10 * (s[l + 1] - '0') + s[l + 2] - '0';
}

int main(int argc, const char * argv[]) {
    while (scanf("%d %d", &n, &m) == 2) {
        init();
        for (int i = 0; i < n; i ++) {
            for (int j = 0; j < m; j ++) {
                scanf("%s", s);
                if(s[3] == 'X') continue;
                if(s[3] == '.') {
                    Tu[i][j].r = Tu[i][j - 1].r;
                    Tu[i][j].c = Tu[i - 1][j].c;
                    row[Tu[i][j].r] --;
                    col[Tu[i][j].c] --;
                    rec[i][j] = 0;
                }else {
                    int d1 = GetNum(0, 2), d2 = GetNum(4, 6);
                    if(d2 != -1) {
                        row[++rn] = d2; Tu[i][j].r = rn;
                    }
                    if(d1 != -1) {
                        col[++cn] = d1; Tu[i][j].c = cn;
                    }
                }
            }
        }
        S = 0; T = rn + cn + 1;
        for (int i = 1; i <= rn; i ++) addEdge(S, i, row[i]);
        for (int i = 1; i <= cn; i ++) addEdge(i + rn, T, col[i]);
        for (int i = 0; i < n; i ++) {
            for (int j = 0; j < m; j ++) {
                if(rec[i][j] != -1) {
                    addEdge(Tu[i][j].r, Tu[i][j].c + rn, 8);
                    rec[i][j] = tot - 2;
                }
            }
        }
        dinic();
        for (int i = 0; i < n; i ++) {
            for (int j = 0; j < m; j ++) {
                if(rec[i][j] == -1) printf("_");
                else printf("%d", 9 - edge[rec[i][j]].w);
                 if(j != m - 1) printf(" ");
            }
            printf("\n");
        }

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henu_jizhideqingwa/article/details/81983122