Kakuro Extension【最大流】

HDU-3338

这道题真的处理起来好复杂啊,题意就是个简单的方格填数问题,但是每个白点至少放1,那么最后的可能解是怎样的呢?我们是不是要把x轴上的和y轴上的统一起来,然后就是每个点都被对应的x和y匹配起来,那么,之后,用每个点的x向y建立边,跑最大流,每个点的放的值就是反向边的权值了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(x, y) make_pair(x, y)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e2 + 7, maxE = 1e5 + 7, st = 0;
pair<int, int> re_xy[20007];
int N, M, head[20007], cur[20007], cnt, ed, id[maxN][maxN], tot, ou[maxN][maxN];
char mp[maxN][maxN][10];
int down[maxN][maxN], righ[maxN][maxN];
struct Eddge
{
    int nex, to, flow;
    Eddge(int a=-1, int b=0, int c=0):nex(a), to(b), flow(c) {}
}edge[maxE];
inline void addEddge(int u, int v, int w)
{
    edge[cnt] = Eddge(head[u], v, w);
    head[u] = cnt++;
}
inline void _add(int u, int v, int w) { addEddge(u, v, w); addEddge(v, u, 0); }
inline void solve(int x, int y)
{
    if(mp[x][y][1] == ‘X‘ && mp[x][y][7] == ‘X‘) { id[x][y] = -1; return; }
    if(mp[x][y][1] == ‘.‘) { return; }
    re_xy[++tot] = MP(x, y);
    id[x][y] = tot;
    down[x][y] = righ[x][y] = 0;
    if(mp[x][y][1] != ‘X‘) for(int i=1; i<=3; i++) down[x][y] = down[x][y] * 10 + mp[x][y][i] - ‘0‘;
    if(mp[x][y][5] != ‘X‘) for(int i=5; i<=7; i++) righ[x][y] = righ[x][y] * 10 + mp[x][y][i] - ‘0‘;
}
int deep[20007];
queue<int> Q;
inline bool bfs()
{
    for(int i=0; i<=ed; i++) deep[i] = 0;
    deep[st] = 1;
    while(!Q.empty()) Q.pop();
    Q.push(st);
    while(!Q.empty())
    {
        int u = Q.front(); Q.pop();
        for(int i=head[u], v, f; ~i; i=edge[i].nex)
        {
            v = edge[i].to; f = edge[i].flow;
            if(f && !deep[v])
            {
                deep[v] = deep[u] + 1;
                Q.push(v);
            }
        }
    }
    return deep[ed];
}
int  dfs(int u, int Dist)
{
    if(u == ed) return Dist;
    for(int &i=cur[u], v, f; ~i; i=edge[i].nex)
    {
        v = edge[i].to; f = edge[i].flow;
        if(f && deep[v] == deep[u] + 1)
        {
            int di = dfs(v, min(Dist, f));
            if(di)
            {
                edge[i].flow -= di;
                edge[i^1].flow += di;
                return di;
            }
        }
    }
    return 0;
}
inline int Dinic()
{
    int ans = 0, tmp;
    while(bfs())
    {
        for(int i=0; i<=ed; i++) cur[i] = head[i];
        while((tmp = dfs(st, INF))) ans += tmp;
    }
    return ans;
}
inline void init()
{
    cnt = tot = 0;
    memset(head, -1, sizeof(head));
    memset(id, 0, sizeof(id));
}
int main()
{
    while(scanf("%d%d", &N, &M) != EOF)
    {
        init();
        for(int i=1; i<=N; i++)
        {
            for(int j=1; j<=M; j++)
            {
                scanf("%s", mp[i][j] + 1);
                solve(i, j);
            }
        }
        ed = (tot << 1) + 1;
        for(int i=1, le_id=0, up_id=0; i<=N; i++)
        {
            for(int j=1; j<=M; j++)
            {
                if(mp[i][j][1] == ‘.‘)
                {
                    for(int dx = i - 1; dx > 0; dx--)
                    {
                        if(id[dx][j])
                        {
                            up_id = dx;
                            down[dx][j]--;
                            break;
                        }
                    }
                    for(int dy = j - 1; dy > 0; dy--)
                    {
                        if(id[i][dy])
                        {
                            le_id = dy;
                            righ[i][dy]--;
                            break;
                        }
                    }
                    _add(id[i][le_id], id[up_id][j] + tot, 8);
                }
            }
        }
        for(int i=1; i<=N; i++)
        {
            for(int j=1; j<=M; j++)
            {
                if(id[i][j] > 0)
                {
                    if(mp[i][j][1] != ‘X‘) _add(id[i][j] + tot, ed, down[i][j]);
                    if(mp[i][j][5] != ‘X‘) _add(st, id[i][j], righ[i][j]);
                }
            }
        }
        Dinic();
        for(int x = 1; x <= tot; x++)
        {
            for(int i=head[x], y, f; ~i; i=edge[i].nex)
            {
                y = edge[i].to; f = edge[i^1].flow;
                if(y == st) continue;
                ou[re_xy[x].first][re_xy[y - tot].second] = f;
            }
        }
        for(int i=1; i<=N; i++)
        {
            for(int j=1; j<=M; j++)
            {
                if(mp[i][j][1] != ‘.‘) printf("_");
                else printf("%d", ou[i][j] + 1);
                printf("%c", j == M ? ‘\n‘ : ‘ ‘);
            }
        }
    }
    return 0;
}
/*
3 3
XXXXXXX 009/XXX XXXXXXX
XXX/009 ....... XXXXXXX
XXXXXXX XXXXXXX XXXXXXX
*/

原文地址:https://www.cnblogs.com/WuliWuliiii/p/11266490.html

时间: 2024-11-02 02:53:52

Kakuro Extension【最大流】的相关文章

HDU-3338 Kakuro Extension(最大流,方格横纵和问题)

题目链接:HDU-3338 Kakuro Extension 题意 给出一个$n\times m$的网格,每个格子为黑色或白色,对于一行中连续的若干个白色格子,我们要往这若干个白色格子中填入$1\sim 9$的数字,使其和等于左边黑色格子中的一个已知数字$a_1$:对于一列中连续的若干个白色格子,同理填入$1\sim 9$的数字使其和等于上边黑色格子中的一个已知数字$a_2$.如果一个黑色格子相邻的右边和下边都有白色格子,那么这个黑色格子是带有两个已知数字$a_1$和$a_2$的,分别代表右边和

HDU3338 Kakuro Extension(最大流+思维构图)

这道题一定要写一下,卡了好久. 题意: 有黑白两种方格,最上边一行和最左边一列一定是黑色,然后其余的地方有可能是黑色,有可能是白色,和白色相邻的黑色方格里有数字(1个或2个), 现在要求在白色方格里填1~9中的一个数字,使得一个黑色方格下边的数字 = sigma(该黑色方格下边白色方格数字)  这个sigma不是下边全部的白方格, 而是一直往下走一直走到一个黑方格之前所有的白方格,详情见样例1.相同的,黑方格右上角的数字 = sigma(该黑色方格右边白色方格数字). 思路: 可以很容易看出,所

HDU - 3338 Kakuro Extension(最大流)

题目大意:看一下图基本就知道了 解题思路:难点是构图.. 设置一个超级源点和所有的行的和相连,容量为该行的和 - 该行和由几个数相加得到 设置一个超级汇点,和所有列的和相连,容量为该列的和 - 该列和由几个数相加得到 接着就是空白部分和 "行和"和 "列和"的关系了 空白连向该行的行和,权值为8 空白连向该列的列和,权值也为8 为什么为8,而不是9,因为流量也可能为0,但是0是不能填的,所以将容量设为8,最后取值的时候加1即可 #include <cstdio

hdu 3338 Kakuro Extension(最大流)

hdu 3338 Kakuro Extension Description If you solved problem like this, forget it.Because you need to use a completely different algorithm to solve the following one. Kakuro puzzle is played on a grid of "black" and "white" cells. Apart

hdoj 3338 Kakuro Extension 【经典最大流+输出流量】

题目:hdoj 3338 Kakuro Extension 定义:神级最大流(各种错误无数次,整整一天) 题意:一个游戏,这个游戏给出一个矩阵,有些矩阵里面有两个数,前面一个数表示从下一行到下一个出现数字行的所有数字和(当前这一列),而第二个数表示从下一列到下一个出现数字的列(当前这一行),让你填入满足条件的数字的矩阵(1---9),可以重复(最大流条件). 分析:首先数字可以重复那么确定了可以用最大流来做,建图方法就是列进行出,或者行进列出,前者比较好写. 这个题目还有一个条件就是要求必须有流

Kakuro Extension (hdu 3338 最大流 建图难)

Kakuro Extension Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1093    Accepted Submission(s): 377 Special Judge Problem Description If you solved problem like this, forget it.Because you nee

hdu 3344 Kakuro Extension Extension

Kakuro Extension Extension Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 468    Accepted Submission(s): 240 Problem Description You know ,I'm a lazy guy and write problem description is a ver

HDU 3338 Kakuro Extension(网络流)

HDU 3338 Kakuro Extension 题目链接 题意:完成如图的游戏,填充数字1-9 思路:网络流的行列模型,把每行每列连续的一段拆分出来建图即可,然后题目有限制一个下限1,所以 每行每列的容量减去相应的数字,然后建图建容量8就好,这样就默认原来容量已经有1了 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespac

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

题意:有一个填数字的游戏,需要你为白色的块内填一些值,不过不能随意填的,是有一些规则的(废话),在空白的上方和作方给出一些值,如果左下角有值说明下面列的和等于这个值,右上角的值等于这行后面的数的和,如下图示,现在把空白的地方填上数字即可(只能填从1~9的数字,不限制一行是否有重复数字). 分析:如果这道题不在网络流专题里面估计很难向网络流这样面去想(看不出来),不过如果刻意往这个地方想的话还是能想到的,首先可以观察出来行的和等于列的和,所以用行和列的一边当源一边当汇,然后用每个白块与相对应的行列