HDU3338Kakuro Extension(最大流,ISAP)建图是关键

Kakuro Extension

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1144    Accepted Submission(s): 404

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

题意:输入一个n,m,表示表格有n行m列,黑格子里的数子分水平与垂直,如果一个数在 “\” 的右方表示这个数由当前格子的水平右方连续的白格子内的数的总和(白格子内的数需要填写,范围:1 ~ 9),如果一个数在左方,由当前垂直下方连续的白格子内的数的总和。所以每个白格了恰好用了两次,一次水平,一次垂直。给出的表格填写白格子内的数时总是有答案的。填写方式任何一种满足条件即可(白格子内所填的数至少为1)。

解析:一开始看了题后无从下手啊,看了网上的解题报告,用网络流解。关键是理解怎么建图。为什么会想到网络流来解题呢,1:从水平方向看,所有的水平方向白格子内数的总和恰好等于垂直方向上的白格内数的总和,总流入量==总流出量。2:每个白格子恰好用了两次,一次是水平一次是垂直,流入点的边与流出点的边都只有一条边,   量的入出是相等的,也就是白格子内所填的数子。

建图:分下列几类点。

S:超极源点

A ::黑格子内水平方向的数看成一个点。

B  :白格子。

C:黑格子内垂直方向的数看成另一个点。

T:超极汇点

图中的边:

(S , A  , capcity): capcity为边的容量=A点的数  -  水平右方连续白格子的个数(保证了白格子内的数至少为1)

(A , B ,  8):容量为8:保证了白格子内的数至少为1(白格子点的入边)

(B , C , 8):同理(白格子点的出边)

(C ,  T  ,capcity):  capcity为边的容量=C点的数  - 垂直下方连续白格子的个数

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define captype int

const int MAXN = 100010;   //点的总数
const int MAXM = 400010;    //边的总数
const int INF = 1<<30;
struct EDG{
    int to,next;
    captype cap,flow;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN];  //每种距离(或可认为是高度)点的个数
int dis[MAXN];  //每个点到终点eNode 的最短距离
int cur[MAXN];  //cur[u] 表示从u点出发可流经 cur[u] 号边

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
//有向边 三个参数,无向边4个参数
void addEdg(int u,int v,captype c,captype rc=0){
    edg[eid].to=v; edg[eid].next=head[u];
    edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v];
    edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;
}
//预处理eNode点到所有点的最短距离
void BFS(int sNode, int eNode){
    queue<int>q;
    memset(gap,0,sizeof(gap));
    memset(dis,-1,sizeof(dis));
    gap[0]=1;
    dis[eNode]=0;
    q.push(eNode);
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=head[u]; i!=-1; i=edg[i].next){
            int v=edg[i].to;
            if(dis[v]==-1){
                dis[v]=dis[u]+1;
                gap[dis[v]]++;
                q.push(v);
            }
        }
    }
}
int node_f[MAXN]; //记实际流过每个点的值,也就是正向流过当前点的值,而非回流
int S[MAXN];    //路径栈,存的是边的id号
captype maxFlow_sap(int sNode,int eNode, int n){  //注意:n为点的总个数,包括源点与汇点
    BFS(sNode, eNode);              //预处理eNode到所有点的最短距离
    if(dis[sNode]==-1) return 0;    //源点到不可到达汇点
    memcpy(cur,head,sizeof(head));
    memset(node_f,0,sizeof(node_f));

    int top=0;  //栈顶
    captype ans=0;  //最大流
    int u=sNode;
    while(dis[sNode]<n){   //判断从sNode点有没有流向下一个相邻的点
        if(u==eNode){   //找到一条可增流的路
            captype Min=INF ;
            int inser;
            for(int i=0; i<top; i++)    //从这条可增流的路找到最多可增的流量Min
            if(Min>edg[S[i]].cap-edg[S[i]].flow){
                Min=edg[S[i]].cap-edg[S[i]].flow;
                inser=i;
            }
            for(int i=0; i<top; i++){
                edg[S[i]].flow+=Min;
                edg[S[i]^1].flow-=Min;  //可回流的边的流量
                if(edg[S[i]].cap>0)
                    node_f[edg[S[i]].to]=edg[S[i]].flow;
                else
                    node_f[edg[S[i]^1].to]=edg[S[i]^1].flow;
            }
            ans+=Min;
            top=inser;  //从这条可增流的路中的流量瓶颈 边的上一条边那里是可以再增流的,所以只从断流量瓶颈 边裁断
            u=edg[S[top]^1].to;  //流量瓶颈 边的起始点
            continue;
        }
        bool flag = false;  //判断能否从u点出发可往相邻点流
        int v;
        for(int i=cur[u]; i!=-1; i=edg[i].next){
            v=edg[i].to;
            if(edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){
                flag=true;
                cur[u]=i;
                break;
            }
        }
        if(flag){
            S[top++] = cur[u];  //加入一条边
            u=v;
            continue;
        }
        //如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1
        int Mind= n;
        for(int i=head[u]; i!=-1; i=edg[i].next)
        if(edg[i].cap-edg[i].flow>0 && Mind>dis[edg[i].to]){
            Mind=dis[edg[i].to];
            cur[u]=i;
        }
        gap[dis[u]]--;
        if(gap[dis[u]]==0) return ans;  //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径
                                        //因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流
        dis[u]=Mind+1;      //如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1
        gap[dis[u]]++;
        if(u!=sNode) u=edg[S[--top]^1].to;  //退一条边

    }
    return ans;
}
struct NODE{
    char num[10];
    int num1,num2;
    int id1,id2;    //点的编号
}mapt[105][105];
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)>0){
        init();
        int k=1;
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++){
                scanf("%s",mapt[i][j].num);
                char ss[10];
                strcpy(ss,mapt[i][j].num);
                mapt[i][j].num1=-1;
                mapt[i][j].num2=-1;
                mapt[i][j].id1=-1;
                mapt[i][j].id2=-1;
                if(ss[0]=='.')
                    mapt[i][j].id1=k++;
                if(ss[0]>='0'&&ss[0]<='9'){
                    mapt[i][j].num1=(ss[0]-'0')*100+(ss[1]-'0')*10+ss[2]-'0';
                    mapt[i][j].id1=k++;
                }
                if(ss[4]>='0'&&ss[4]<='9'){
                    mapt[i][j].num2=(ss[4]-'0')*100+(ss[5]-'0')*10+ss[6]-'0';
                    mapt[i][j].id2=k++;
                }
            }

        int s=0 , t = k ;
        for(int i=0; i<n; i++){
            int j=0;
            while(j<m){
                while(j<m&&mapt[i][j].num2==-1)j++;    //找一个水平方向有值的格子
                if(j>=m) break;
                int u=mapt[i][j].id2 ,c=mapt[i][j].num2 ,tk=0;
                j++;
                while(j<m&&mapt[i][j].num[0]=='.'){
                    int v=mapt[i][j].id1;
                    addEdg(u,v,8);
                    j++; tk++;
                }
                addEdg(s,u,c-tk); //记得要减空格子的个数,因为每个空格子值至少为1
            }
        }
        for(int j=0; j<m; j++){
            int i=0;
            while(i<n){
                while(i<n&&mapt[i][j].num1==-1)i++;
                if(i>=n) break;
                int v=mapt[i][j].id1 , c=mapt[i][j].num1 ,tk=0;
                i++;
                while(i<n&&mapt[i][j].num[0]=='.'){
                    int u=mapt[i][j].id1;
                    addEdg(u,v,8);
                    i++; tk++;
                }
                addEdg(v,t,c-tk);
            }
        }

        maxFlow_sap(s,t,k+1);
        for(int i=0; i<n; i++){
            int j;
            for(j=0; j<m-1; j++)
                if(mapt[i][j].num[0]=='.')
                    printf("%d ",node_f[mapt[i][j].id1]+1);
                else
                    printf("_ ");

            if(mapt[i][j].num[0]=='.')
                printf("%d\n",node_f[mapt[i][j].id1]+1);
            else
                printf("_\n");
        }
    }
}
时间: 2024-11-12 11:53:12

HDU3338Kakuro Extension(最大流,ISAP)建图是关键的相关文章

poj3281-Dining ,最大流,建图

点击打开链接 分析: 求最大流 建图: 拆点 牛拆成左边与食物相连的左牛 和 右边与饮料相连的右牛 1.s->食物 连边 2.食物->左牛 3.左牛->右牛 4.右牛->饮料 5.饮料->t 边的方向为 s->食物->左牛->右牛->饮料->t #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #i

HDU 3376--Matrix Again【最大费用最大流 &amp;&amp; 经典建图】

Matrix Again Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Submission(s): 3457    Accepted Submission(s): 1020 Problem Description Starvae very like play a number game in the n*n Matrix. A positive intege

POJ 2112 最大流+二分+(建图:最重要的)

Optimal Milking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 12521   Accepted: 4524 Case Time Limit: 1000MS Description FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among the C (1 <= C <= 200) co

【BZOJ-2879】美食节 最小费用最大流 + 动态建图

2879: [Noi2012]美食节 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1366  Solved: 737[Submit][Status][Discuss] Description CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽管所有的菜品都很可口,厨师做菜的速度也很快,小M仍然觉得自己桌上没有已经摆在别人

POJ 3281【拆点 &amp;&amp; 最大流经典建图】

Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11097   Accepted: 5096 Description Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others. Farmer John has cooked fabulo

HDU 3667-- Transportation【最小费最大流 &amp;&amp; 拆边建图 &amp;&amp; 经典】

Transportation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2441    Accepted Submission(s): 1041 Problem Description There are N cities, and M directed roads connecting them. Now you want to

HPU 2686--Matrix【最大费用最大流 &amp;&amp; 经典建图】

Matrix Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2062    Accepted Submission(s): 1074 Problem Description Yifenfei very like play a number game in the n*n Matrix. A positive integer numbe

HDU3572Task Schedule(最大流 ISAP比较快)建图方法不错

Task Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5007    Accepted Submission(s): 1636 Problem Description Our geometry princess XMM has stoped her study in computational geometry t

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

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