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

本文介绍了解决Kakuro扩展版拼图问题所使用的算法,详细阐述了问题描述、输入输出格式以及实现思路,包括使用网络流算法解决实际问题的过程。文章通过实例分析,展示了如何利用特定建图方法简化复杂度,最终输出解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
NotOnlySuccess@HDU
 

Source
 

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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值