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

这道题一定要写一下,卡了好久。

题意:

有黑白两种方格,最上边一行和最左边一列一定是黑色,然后其余的地方有可能是黑色,有可能是白色,和白色相邻的黑色方格里有数字(1个或2个),

现在要求在白色方格里填1~9中的一个数字,使得一个黑色方格下边的数字 = sigma(该黑色方格下边白色方格数字)  这个sigma不是下边全部的白方格,

而是一直往下走一直走到一个黑方格之前所有的白方格,详情见样例1。相同的,黑方格右上角的数字 = sigma(该黑色方格右边白色方格数字)。

思路:

可以很容易看出,所有白色方格的行相加 == 所有白色方格列相加  也就是  所有黑色方格右上角数字和 == 所有黑色方格左下角数字和。那么符合网络流,

源点输入的流量==汇点汇入的流量。建立超级源点sp和超级汇点tp,然后进行以下设定:

type = 0,不带数字的黑色方格

type = 1,白色方格

type = 2,带有两个数字的黑色方格(这个要进行拆点,代码里会标记)

type = 3,只有左下角带数字的黑色方格

type = 4,只有右上角带数字的黑色方格

把黑色方格左下角作为源点,白色方格作为中间点,黑色方格右上角作为汇点。(也可以源点汇点交换一下,如下一行的括号)

接下来进行连边 sp -> type2.3 -> type1 -> type2.4 -> tp。(也可以sp -> type2.4 -> type1 -> type2.3 -> tp)

因为白方格要填1~9有下界1和上界9两个界线,不如让填的数减一,最后再加上,就变成了填0~8可以方便的进行最大流操作

sp -> type2.3连边时,边权为左下角的数减去下边白色方格数*1(因为都减1了)

type2.4 -> tp连边时,边权为右上角的数减去右边白色方格数*1

type2.3 -> type1 -> type2.4连边时,边权设为8

然后跑最大流,求答案

#include <bits/stdc++.h>
using namespace std;

const int maxn = 100 + 5;
const int maxm = 1e6 + 5;
const int inf = 0x3f3f3f3f;
int n, m, d[maxn*maxn], sp, tp, maxflow;
int head[maxn*maxn], tot;
struct point{
    int top, lft, type;
} mp[maxn][maxn];
struct edge{
    int to, w, next;
} ed[maxm];
int num[maxn][maxn], ans[maxn*maxn];
char s[10];
inline void add( int u, int v, int w ){
    ed[++tot].to = v; ed[tot].w = w; ed[tot].next = head[u]; head[u] = tot;
    ed[++tot].to = u; ed[tot].w = 0; ed[tot].next = head[v]; head[v] = tot;
}

inline void init(){
    memset( head, -1 ,sizeof(head) );
    tot = 1;
}

inline void map_set(){
    for( int i=0; i<n; i++ )
        for( int j=0; j<m; j++ ){
            int cnt = 0;
            if( mp[i][j].type==4 ){
                for( int k=j+1; k<m && mp[i][k].type==1; k++ )
                    add( num[i][k], num[i][j], 8 ), cnt ++;
                add( num[i][j], tp, mp[i][j].top-cnt );
            }else if( mp[i][j].type==2 ){
                for( int k=j+1; k<m && mp[i][k].type==1; k++ )
                    add( num[i][k], num[i][j], 8 ), cnt ++;
                add( num[i][j], tp, mp[i][j].top-cnt );
                cnt = 0;
                for( int k=i+1; k<n && mp[k][j].type==1; k++ )
                    add( num[i][j]-1, num[k][j], 8 ), cnt ++;       //type==2时,让num[i][j]-1代表左下数字的点
                add( sp, num[i][j]-1, mp[i][j].lft-cnt );
            }else if( mp[i][j].type==3 ){
                for( int k=i+1; k<n && mp[k][j].type==1; k++ )
                    add( num[i][j], num[k][j], 8 ), cnt ++;
                add( sp, num[i][j], mp[i][j].lft-cnt );
            }
        }
}

inline bool bfs(){
    memset( d, 0, sizeof(d) );
    queue<int> q;
    d[sp] = 1;
    q.push(sp);
    while( !q.empty() ){
        int x = q.front();
        q.pop();
        for( int i=head[x]; i!=-1; i=ed[i].next ){
            int y = ed[i].to;
            if( ed[i].w && !d[y] ){
                d[y] = d[x] + 1;
                q.push(y);
                if( y==tp ) return 1;
            }
        }
    }
    return 0;
}

inline int min( int a, int b ){
    return a<b ? a:b;
}

inline int dfs( int x, int flow ){
    if( x==tp ) return flow;
    int rest = flow, k;
    for( int i=head[x]; i!=-1 && rest; i=ed[i].next ){
        int y = ed[i].to;
        if( ed[i].w && d[y]==d[x]+1 ){
            k = dfs( y, min(rest, ed[i].w) );
            if(!k) d[y] = 0;
            ed[i].w -= k;
            ed[i^1].w += k;
            rest -= k;
        }
    }
    return flow - rest;
}

inline void dinic(){
    int flow = maxflow = 0;
    while( bfs() ){
        while( flow=dfs(sp, inf) ) maxflow += flow;     //该题里 maxflow没什么用,可以不求
    }
}

inline void output(){
    memset( ans, 0, sizeof(ans) );                  //ans记录答案
    for( int i=head[sp]; i!=-1; i=ed[i].next ){     //超级源点sp是虚拟的,正好利用它进行遍历
        int u = ed[i].to;
        for( int j=head[u]; j!=-1; j=ed[j].next )
            ans[ed[j].to] = 8 - ed[j].w + 1;        //最后要加回1(其实这里为什么要减去边权而不直接用边权我不是很懂,求dalao指教)
    }
    for( int i=0; i<n; i++ ){
        putchar(‘_‘);
        for( int j=1; j<m; j++ ){
            if( mp[i][j].type!=1 ) printf(" _");
            else printf("%2d", ans[num[i][j]]);
        }
        puts("");
    }
}

int main(){
    // freopen("in.txt", "r", stdin);
    while( ~scanf("%d%d", &n, &m) ){
        init();
        int nump = 0;
        for( int i=0; i<n; i++ )
            for( int j=0; j<m; j++ ){
                scanf("%s", s);
                if( s[0]==‘.‘ ){
                    mp[i][j].type = 1;
                    mp[i][j].top = mp[i][j].lft = 0;
                }else if( s[0]==‘X‘ ){
                    if( s[4]==‘X‘ ) mp[i][j].type = 0;
                    else{
                        mp[i][j].type = 4;
                        mp[i][j].lft = 0;
                        mp[i][j].top = (s[4]-‘0‘)*100 + (s[5]-‘0‘)*10 + s[6]-‘0‘;
                    }
                }else{
                    if( s[4]==‘X‘ ){
                        mp[i][j].type = 3;
                        mp[i][j].lft = (s[0]-‘0‘)*100 + (s[1]-‘0‘)*10 + s[2]-‘0‘;
                        mp[i][j].top = 0;
                    }else{
                        mp[i][j].type = 2;
                        mp[i][j].lft = (s[0]-‘0‘)*100 + (s[1]-‘0‘)*10 + s[2]-‘0‘;
                        mp[i][j].top = (s[4]-‘0‘)*100 + (s[5]-‘0‘)*10 + s[6]-‘0‘;
                    }
                }
                if( mp[i][j].type==2 ) nump += 2;           //type == 2的时候就是上半部分和左半部分都有数字,那么将其拆点成两个点
                else nump ++;
                num[i][j] = nump;           //将矩阵的二维编码转换成一维,便于进行操作
            }
        sp = 0; tp = nump+1;
        map_set();
        dinic();
        output();
    }

    return 0;
}

原文地址:https://www.cnblogs.com/WAautomaton/p/10992351.html

时间: 2024-08-29 20:11:53

HDU3338 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$的,分别代表右边和

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

POJ 3189 Steady Cow Assignment(网络流之最大流+二分构图)

题目地址:POJ 3189 我晕啊...飞快的把白天的任务完成又有什么用...节省下来的时间活生生的被我的手残给全浪费掉了...又调了一整天,问题居然是一个地方的n和m写反了!!!反思..反思...面壁去... 这题就是二分区间,然后枚举区间位置.然后建图就行了.不多说.. 代码如下: #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include

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

Kakuro Extension【最大流】

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