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 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 from the top row and leftmost column which are entirely black, the grid has some amount of white cells which form "runs" and some amount of black cells. "Run" is a vertical or horizontal
maximal one-lined block of adjacent white cells. Each row and column of the puzzle can contain more than one "run". Every white cell belongs to exactly two runs — one horizontal and one vertical run. Each horizontal "run" always has a number in the black half-cell
to its immediate left, and each vertical "run" always has a number in the black half-cell immediately above it. These numbers are located in "black" cells and are called "clues".The rules of the puzzle are simple:

1.place a single digit from 1 to 9 in each "white" cell

2.for all runs, the sum of all digits in a "run" must match the clue associated with the "run"

Given the grid, your task is to find a solution for the puzzle.

              

        Picture of the first sample input            Picture of the first sample output

Input

The first line of input contains two integers n and m (2 ≤ n,m ≤ 100) — the number of rows and columns correspondingly. Each of the next n lines contains descriptions of m cells. Each cell description is one of the following 7-character strings:

.......— "white" cell;

XXXXXXX— "black" cell with no clues;

AAA\BBB— "black" cell with one or two clues. AAA is either a 3-digit clue for the corresponding vertical run, or XXX if there is no associated vertical run. BBB is either a 3-digit clue for the corresponding horizontal run, or XXX if there is no associated
horizontal run.

The first row and the first column of the grid will never have any white cells. The given grid will have at least one "white" cell.It is guaranteed that the given puzzle has at least one solution.

Output

Print n lines to the output with m cells in each line. For every "black" cell print ‘_‘ (underscore), for every "white" cell print the corresponding digit from the solution. Delimit cells with a single space, so that each row consists of 2m-1 characters.If
there are many solutions, you may output any of them.

Sample Input

6 6
XXXXXXX XXXXXXX 028\XXX 017\XXX 028\XXX XXXXXXX
XXXXXXX 022\022 ....... ....... ....... 010\XXX
XXX\034 ....... ....... ....... ....... .......
XXX\014 ....... ....... 016\013 ....... .......
XXX\022 ....... ....... ....... ....... XXXXXXX
XXXXXXX XXX\016 ....... ....... XXXXXXX XXXXXXX
5 8
XXXXXXX 001\XXX 020\XXX 027\XXX 021\XXX 028\XXX 014\XXX 024\XXX
XXX\035 ....... ....... ....... ....... ....... ....... .......
XXXXXXX 007\034 ....... ....... ....... ....... ....... .......
XXX\043 ....... ....... ....... ....... ....... ....... .......
XXX\030 ....... ....... ....... ....... ....... ....... XXXXXXX

Sample Output

_ _ _ _ _ _
_ _ 5 8 9 _
_ 7 6 9 8 4
_ 6 8 _ 7 6
_ 9 2 7 4 _
_ _ 7 9 _ _
_ _ _ _ _ _ _ _
_ 1 9 9 1 1 8 6
_ _ 1 7 7 9 1 9
_ 1 3 9 9 9 3 9
_ 6 7 2 4 9 2 _

Author

[email protected]

Source

HDOJ Monthly Contest – 2010.03.06

Recommend

lcy   |   We have carefully selected several similar problems for you:  1569 1565 3416 3081 3277

题意:n*m的黑白格子,填数字,使白色区域的行列值的和等于有值得黑色区域的相对应的值。

思路:网络流,添加超级源点和汇点,源点和每行中有和值的点相连,汇点和每列中有和值的点相连,每行中有和值的点和该行中对应空白格相连,权值为8,同样每列中有和值的点和该列中对应的空白格相连,权值为8。因为数组开大了,memset时超时了,T了两天,简直了。

后来看到网上的建图方法,是把一整行当作一个点,这样建图简单一点,比我的代码要快。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 11000
#define MAXN 200005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b)  for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b)  for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v)   memset ((t) , v, sizeof(t))
#define sf(n)       scanf("%d", &n)
#define sff(a,b)    scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf          printf
#define DBG         pf("Hi\n")
typedef long long ll;
using namespace std;

struct Edge
{
    int u,v,cap,next;
}edge[MAXN];

int head[maxn],cur[maxn],level[maxn];
int num,n,m,cnt;
int row_sum[101][101],col_sum[101][101];//(i,j)位置的行,列之和
int row_cnt[101],col_cnt[101];
int number_col[101][101];   //行标号
int number_row[101][101];   //列标号
int number_w[101][101]; //空白处标号
int id[101][101];       //相应的边编号,用于最后输出
char str[101][101][8];

void init()
{
    num=0;cnt=1;
    mem(head,-1);
    mem(col_sum,0);
    mem(row_sum,0);
    mem(col_cnt,0);
    mem(row_cnt,0);
    mem(number_col,0);
    mem(number_row,0);
    mem(number_w,0);
    mem(id,0);
}

void addedge(int u,int v,int w)
{
    edge[num].u=u; edge[num].v=v; edge[num].cap=w; edge[num].next=head[u]; head[u]=num++;
    edge[num].u=v; edge[num].v=u; edge[num].cap=0; edge[num].next=head[v]; head[v]=num++;
}

bool bfs(int s,int t)
{
    mem(level,-1);
    queue<int>Q;
    Q.push(s);
    level[s]=0;
    while (!Q.empty())
    {
        int u=Q.front(); Q.pop();
        for (int i=head[u];i+1;i=edge[i].next)
        {
            int v=edge[i].v;
            if (level[v]==-1&&edge[i].cap>0)
            {
                level[v]=level[u]+1;
                Q.push(v);
            }
        }
    }
    return level[t]!=-1;
}

int dfs(int u,int t,int f)
{
    if (u==t) return f;
    for (int &i=cur[u];i+1;i=edge[i].next)
    {
        int v=edge[i].v;
        if (level[v]==level[u]+1&&edge[i].cap>0)
        {
            int d=dfs(v,t,min(f,edge[i].cap));
            if (d>0)
            {
                edge[i].cap-=d;
                edge[i^1].cap+=d;
                return d;
            }
        }
    }
    return 0;
}

int dinic(int s,int t,int node)
{
    int flow=0;
    while (bfs(s,t))
    {
        for (int i=0;i<=node;i++) cur[i]=head[i];
        int f;
        while ((f=dfs(s,t,INF))>0)
            flow+=f;
    }
    return flow;
}

void build()    //建图
{
    int i,j;
    for (i=0;i<n;i++)
    {
        for (j=0;j<m;j++)
        {
            scanf("%s",str[i][j]);
            if (isdigit(str[i][j][0]))
            {
                int t=(str[i][j][0]-'0')*100+(str[i][j][1]-'0')*10+str[i][j][2]-'0';
                col_sum[i][j]=t;    //保存下(i,j)位置表示的该行数字之和
                number_col[i][j]=cnt++; //点编号
            }
            if (isdigit(str[i][j][4]))
            {
                int t=(str[i][j][4]-'0')*100+(str[i][j][5]-'0')*10+str[i][j][6]-'0';
                row_sum[i][j]=t;    //保存下(i,j)位置表示的该列数字之和
                number_row[i][j]=cnt++;
            }
            if (str[i][j][0]=='.')
            {
                col_cnt[j]++;   //记录第j列空白格的数目
                row_cnt[i]++;   //记录第i行空白格的数目
                number_w[i][j]=cnt++;   //给空白格编号
            }
        }
    }
    for (i=0;i<n;i++)
    {
        for (j=0;j<m;j++)
        {
            if (number_row[i][j]!=0)
            {
                int all=0,k=j+1;
                while (k>=0&&k<m&&number_w[i][k])
                {
                    all++;
                    id[i][k]=num;   //记录边的序号
                    addedge(number_row[i][j],number_w[i][k],8); //(i,j)位置和这一行后面的空白格连边
                    k++;
                }
                addedge(0,number_row[i][j],row_sum[i][j]-all);
            }
            if (number_col[i][j]!=0)
            {
                int all=0,k=i+1;
                while (k>=0&&k<n&&number_w[k][j])
                {
                    all++;
                    addedge(number_w[k][j],number_col[i][j],8);//(i,j)位置和这一列下面的空白格连边
                    k++;
                }
                addedge(number_col[i][j],cnt,col_sum[i][j]-all);
            }
        }
    }
}

int main()
{
    int i,j;
    while (~scanf("%d%d",&n,&m))
    {
        init();
        build();
        int x=dinic(0,cnt,cnt+1);
        for (i=0;i<n;i++)
        {
            for (j=0;j<m;j++)
            {
                if (id[i][j])
                    printf("%d",9-edge[id[i][j]].cap);
                else
                    printf("_");
                if (j<m-1) printf(" ");
                else printf("\n");
            }
        }
    }
    return 0;
}
时间: 2024-10-06 14:08:54

Kakuro Extension (hdu 3338 最大流 建图难)的相关文章

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

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

hdu4106 区间k覆盖问题(连续m个数,最多选k个数) 最小费用最大流 建图巧妙

/** 题目:hdu4106 区间k覆盖问题(连续m个数,最多选k个数) 最小费用最大流 建图巧妙 链接:http://acm.hdu.edu.cn/showproblem.php?pid=4106 题意:给你n个数,每连续m个数,最多选k个数,问可以选的数的权值和最大多少. 思路:可以转化为区间k覆盖问题.区间k覆盖问题是每个点最多被k个区间覆盖.本题是每个区间最多选k个点. 刚好相反.我的做法有点不同其他博客那种做法.当然本质一样. 我这里的i就是原来n个数的下标,现在作为图中该数的节点编号

POJ 1149 PIGS(最大流+建图)

题目链接:http://poj.org/problem?id=1149 题意:M个猪圈,N个顾客,每个顾客有一些的猪圈的钥匙,只能购买能打开的猪圈里的猪,而且要买一定数量的猪,每个猪圈有已知数量的猪, 但是猪圈可以重新打开,将猪的个数,重新分配,但是只能将猪往当前打开状态的猪圈里赶,以达到卖出的猪的数量最多. 思路:还是4部分,源点->猪圈->猪圈->汇点 Accepted 976K 63MS C++ 能用EK水的,当然用EK水 #include <iostream> #in

POJ 3281 Dining(最大流建图 &amp;&amp; ISAP &amp;&amp; 拆点)

题目链接:http://poj.org/problem?id=3281 努力练建图ing!!! 题意:有 N 头牛,有 F 种食物和 D 种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料. 第2行-第N+1行.是牛i 喜欢A种食物,B种饮料,及食物种类列表和饮料种类列表. 问最多能使几头牛同时享用到自己喜欢的食物和饮料.->最大流. 本题难点是建图: 思路:一般都是左边一个集合表示源点与供应相连,右边一个集合表示需求与汇点相连. 但是本题,牛作为需求仍然是一个群体,但是供

poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙

/** 题目:poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙 链接:http://poj.org/problem?id=3680 题意:给定n个区间,每个区间(ai,bi),以及权值wi.选出一些区间,满足权值和最大且任何一个点不会被超过k个区间覆盖. 思路: 建图:对于每个区间(ai,bi). ai->bi,cap = 1,cost = -wi; (离散化后的ai,bi) 所有区间的端点放到数组,进行从小到大排序,去重,离散化,在数组内相邻的u端点,v端点.u->

poj 3281 最大流+建图

很巧妙的思想 转自:http://www.cnblogs.com/kuangbin/archive/2012/08/21/2649850.html 本题能够想到用最大流做,那真的是太绝了.建模的方法很妙! 题意就是有N头牛,F个食物,D个饮料. N头牛每头牛有一定的喜好,只喜欢几个食物和饮料. 每个食物和饮料只能给一头牛.一头牛只能得到一个食物和饮料. 而且一头牛必须同时获得一个食物和一个饮料才能满足.问至多有多少头牛可以获得满足. 最初相当的是二分匹配.但是明显不行,因为要分配两个东西,两个东

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

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

River Problem (hdu 3947 流量等式建图 难题 最小费用最大流)

River Problem Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 515    Accepted Submission(s): 209 Problem Description The River of Bitland is now heavily polluted. To solve this problem, the Kin

HDU 4292 Food (建图思维 + 最大流)

(点击此处查看原题) 题目分析 题意:某个餐馆出售f种食物,d种饮料,其中,第i种食物有fi份,第i种饮料有di份:此时有n个人来餐馆吃饭,这n个人必须有一份食物和一份饮料才会留下来吃饭,否则,他将离去,而且每个人只吃某几种食物和饮料,如果某个人留下来,那么必须提供一份他吃的食物和一份他吃饮料,问在这种情况下,最多可以招待多少人. 思路:这类的题目我总结为:最大流受到两个互不影响的物体的影响,这类题目为最大流题目,建边如下: 1)由源点向每一种食物i代表的结点建一条容量为fi的边 2)将每个顾客