HDU3338 Kakuro Extension 网络流 isap

22 篇文章 0 订阅
  这题的题意是给你一个矩阵,填空格,使得每个有数字的格子的下方或左边的空格值相加等于这个数字。这题可以用网络流做,我们可以建立源点到列值的边,和行值到汇点的边,流量设为本身的值减去他对应的空格个数(原因后面会讲),对于每个空格,我们把它对应的每个行值和列值进行建边,边由列值到行值,流量为8,因为题目这里要求的是1到9,如果流量为9的话,就有可能出现0的情况,所以流量要为8.(因为流量是8了,所以我们一开始建立源点到列值的流量需要减去它对应的空格数,因为多一个空格,流量就少了1)。输出的时候答案就是列值到行值通过的流量加1.
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define maxn 5050000
#define mem(a, b) memset(a, b, sizeof(a))
#define inf (1e8 + 7)
using namespace std;

int heads[20005], sizes, d[20005], num[20005], pre[105][105][2], ans[105][105], que[20005], n, m, nn, sink, source;
bool vis[20005];
char ch[10];

struct node
{
    int l, h, x, y;
}nd[20005];

struct edge
{
    int u, v, w, next;
}eg[maxn];

void inits()
{
    mem(vis, 0);
    mem(d, 0);
    mem(num, 0);
    mem(heads, -1);
    mem(pre, -1);
    mem(ans, 0);
    sizes = 0;
    nn = 0;
    return;
}

void add(int u, int v, int w)
{
    eg[sizes].v = v;
    eg[sizes].w = w;
    eg[sizes].next = heads[u];
    heads[u] = sizes++;
    eg[sizes].v = u;
    eg[sizes].w = 0;
    eg[sizes].next = heads[v];
    heads[v] = sizes++;
    return;
}

void get(int a, int b)
{
    if(ch[0] == '.')
    {
        pre[a][b][0] = pre[a][b][1] = 0;
        return;
    }
    if(ch[0] != 'X')
    {
        int tmp = (ch[0] - '0') * 100 + (ch[1] - '0') * 10 + ch[2] - '0';
        nd[++nn].l = tmp;
        nd[nn].h = -1;
        nd[nn].x = a;
        nd[nn].y = b;
        pre[a][b][0] = nn;
    }
    if(ch[4] != 'X')
    {
        int tmp = (ch[4] - '0') * 100 + (ch[5] - '0') * 10 + ch[6] - '0';
        nd[++nn].l = -1;
        nd[nn].h = tmp;
        nd[nn].x = a;
        nd[nn].y = b;
        pre[a][b][1] = nn;
    }
    return;
}

void bfs()
{
    int head = 0, ta = 0;
    mem(vis, 0);
    d[sink] = 0;
    vis[sink] = 1;
    num[0] = 1;
    que[head++] = sink;
    while(ta != head)
    {
        int u = que[ta++];
        for(int i = heads[u];i != -1;i = eg[i].next)
        {
            int v = eg[i].v;
            if(!vis[v])
            {
                vis[v] = 1;
                d[v] = d[u] + 1;
                num[d[v]]++;
                que[head++] = v;
            }
        }
    }
    return;
}

int dfs(int a, int cos)
{
    if(a == sink)
        return cos;
    int dd, lv = cos, mins = nn + 1;
    for(int i = heads[a];i != -1;i = eg[i].next)
    {
        int v = eg[i].v;
        int w = eg[i].w;
        if(w)
        {
            if(d[v] + 1 == d[a])
            {
                dd = min(w, lv);
                dd = dfs(v, dd);
                eg[i].w -= dd;
                eg[i^1].w += dd;
                lv -= dd;
                if(d[source] >= nn + 2)
                    return cos - lv;
                if(!lv)
                    break;
            }
            mins = min(mins, d[v]);
        }
    }
    if(lv == cos)
    {
        num[d[a]]--;
        if(!num[d[a]])
            d[source] = nn + 2;
        d[a] = mins + 1;
        num[d[a]]++;
    }
    return cos - lv;
}

void isap()
{
    int st = source;
    while(d[st] < nn + 2)
        dfs(st, inf);
}

void res(int u)
{
    for(int i = heads[u];i != -1;i = eg[i].next)
    {
        int v = eg[i].v;
        if(nd[v].l != -1&&v != sink)
            ans[nd[u].x][nd[v].y] += (eg[i].w + 1);
    }
    return;
}

int main()
{
    sink = 20004;
    source = 20003;
    while(~scanf("%d%d%*c", &n, &m))
    {
        inits();
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < m;j++)
                scanf("%s%*c", ch), get(i, j);
        }
        for(int i = 1;i <= nn;i++)
        {
            if(nd[i].l != -1)
            {
                for(int j = nd[i].x + 1;j < n;j++)
                {
                    if(!pre[j][nd[i].y][0])
                    {
                        nd[i].l--;
                        for(int k = nd[i].y - 1;k >= 0;k--)
                        {
                            if(nd[pre[j][k][1]].h != -1&&pre[j][k][1] != -1&&pre[j][k][1])
                            {
                                add(i, pre[j][k][1], 8);
                                nd[pre[j][k][1]].h--;
                                break;
                            }
                        }
                    }
                    else
                        break;
                }
                add(source, i, nd[i].l);
            }
        }
        for(int i = 1;i <= nn;i++)
            if(nd[i].h != -1)
                add(i, sink, nd[i].h);
        bfs();
        isap();
        for(int i = 1;i <= nn;i++)
        {
            if(nd[i].h != -1)
                res(i);
        }
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < m;j++)
            {
                if(pre[i][j][0] != 0)
                    printf("_ ");
                else
                    printf("%d ", ans[i][j]);
            }
            printf("\n");
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值