HDU 3338 Kakuro Extension(最大流)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tony5t4rk/article/details/81946839

文章地址:http://henuly.top/?p=787

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 _

题目链接

题目要求在空白格子中填充数字(1~9)使行列之和满足黑格子中给出的数据,数字在行列之中可以重复使用。

建图跑最大流,将源点与每个黑格子行数据相连,流量为黑格子行数据,将黑格子列数据与汇点相连,流量为黑格子列数据,这里有行数据和列数据的黑格子数量不确定,所以要统计编号,之后将每个白格子分别与其对应要求的黑格子行列数据相连,流量为9(因为填充数字只能是1~9),由于白格子内不能填充0,所以将白格子所连的边流量都设置为8,在最后结果再加一,因此所有黑格子的行列数据也要对应变化。

由于题目保证有解,所以最大流必定是源点与每个黑格子行数据流量之和,也等于每个黑格子列数据流量之和,跑最大流白格子所在边的流量结果即为最终结果。

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define XDebug(x) cout<<#x<<"="<<x<<endl;
#define ArrayDebug(x,i) cout<<#x<<"["<<i<<"]="<<x[i]<<endl;
#define print(x) out(x);putchar('\n')
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<double,double> PDD;
typedef pair<ll,ll> PLL;
const int INF = 0x3f3f3f3f;
const int maxn = 1e2 + 5;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double pi = asin(1.0) * 2;
const double e = 2.718281828459;
template <class T>
inline bool read(T &ret) {
    char c;
    int sgn;
    if (c = getchar(), c == EOF) {
        return false;
    }
    while (c != '-' && (c < '0' || c > '9')) {
        c = getchar();
    }
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9') {
        ret = ret * 10 + (c - '0');
    }
    ret *= sgn;
    return true;
}
template <class T>
inline void out(T x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x > 9) {
        out(x / 10);
    }
    putchar(x % 10 + '0');
}

struct Link {
    int V, Weight, Next;
    Link(int _V = 0, int _Weight = 0, int _Next = 0): V(_V), Weight(_Weight), Next(_Next) {}
};

Link edges[2500005];
int Head[maxn * maxn * 2];
int Tot;
int Depth[maxn * maxn * 2];
int Current[maxn * maxn * 2];

int N, M;
int RCnt, CCnt;
char Ans[maxn][maxn];
int Info[maxn][maxn];
int Book[maxn][maxn];
PII Symbol[maxn][maxn];
PII Record[maxn][maxn];

void Init() {
    Tot = 0;
    memset(Head, -1, sizeof(Head));
}

void AddEdge(int U, int V, int Weight, int ReverseWeight = 0, int X = 0, int Y = 0) {
    edges[Tot].V = V;
    edges[Tot].Weight = Weight;
    edges[Tot].Next = Head[U];
    Head[U] = Tot++;
    if (X && Y) {
        Book[X][Y] = Tot;
    }
    edges[Tot].V = U;
    edges[Tot].Weight = ReverseWeight;
    edges[Tot].Next = Head[V];
    Head[V] = Tot++;
}

bool Bfs(int Start, int End) {
    memset(Depth, -1, sizeof(Depth));
    queue<int> Que;
    Depth[Start] = 0;
    Que.push(Start);
    while (!Que.empty()) {
        int Vertex = Que.front();
        Que.pop();
        for (int i = Head[Vertex]; i != -1; i = edges[i].Next) {
            if (Depth[edges[i].V] == -1 && edges[i].Weight > 0) {
                Depth[edges[i].V] = Depth[Vertex] + 1;
                Que.push(edges[i].V);
            }
        }
    }
    return Depth[End] != -1;
}

int Dfs(int Vertex, int End, int NowFlow) {
    if (Vertex == End || NowFlow == 0) {
        return NowFlow;
    }
    int UsableFlow = 0, FindFlow;
    for (int &i = Current[Vertex]; i != -1; i = edges[i].Next) {
        if (edges[i].Weight > 0 && Depth[edges[i].V] == Depth[Vertex] + 1) {
            FindFlow = Dfs(edges[i].V, End, min(NowFlow - UsableFlow, edges[i].Weight));
            if (FindFlow > 0) {
                edges[i].Weight -= FindFlow;
                edges[i ^ 1].Weight += FindFlow;
                UsableFlow += FindFlow;
                if (UsableFlow == NowFlow) {
                    return NowFlow;
                }
            }
        }
    }
    if (!UsableFlow) {
        Depth[Vertex] = -2;
    }
    return UsableFlow;
}

int Dinic(int Start, int End) {
    int MaxFlow = 0;
    while (Bfs(Start, End)) {
        for (int i = 0; i <= RCnt + N * M + CCnt + 1; ++i) {
            Current[i] = Head[i];
        }
        MaxFlow += Dfs(Start, End, INF);
    }
    return MaxFlow;
}

void Build() {
    char Ch[10];
    RCnt = 0, CCnt = 0;
    for (int i = 1; i <= N; ++i) {
        for (int j = 1; j <= M; ++j) {
            Symbol[i][j].first = 0; Symbol[i][j].second = 0;
            Record[i][j].first = 0; Record[i][j].second = 0;
            scanf("%s", Ch);
            if (Ch[3] == 'X') {
                continue;
            }
            else if (Ch[0] == '.') {
                Ans[i][j] = '0';
                Record[i][j].first = Record[i][j - 1].first;
                Record[i][j].second = Record[i - 1][j].second;
                Info[i][Record[i][j].first] -= 1;
                Info[Record[i][j].second][j] -= 1000;
            }
            else {
                if (Ch[0] != 'X') {
                    int Temp = (Ch[0] - '0') * 100 + (Ch[1] - '0') * 10 + (Ch[2] - '0');
                    Info[i][j] = Temp * 1000;
                    Symbol[i][j].first = (++CCnt);
                }
                if (Ch[4] != 'X') {
                    int Temp = (Ch[4] - '0') * 100 + (Ch[5] - '0') * 10 + (Ch[6] - '0');
                    Info[i][j] = Info[i][j] == -1 ? Temp : Info[i][j] + Temp;
                    Symbol[i][j].second = (++RCnt);
                }
                Record[i][j].first = j; Record[i][j].second = i;
            }
        }
    }
    for (int i = 1; i <= N; ++i) {
        for (int j = 1; j <= M; ++j) {
            if (Info[i][j] % 1000) {
                AddEdge(0, Symbol[i][j].second, Info[i][j] % 1000);
            }
            if (Info[i][j] / 1000) {
                AddEdge(RCnt + N * M + Symbol[i][j].first, RCnt + N * M + CCnt + 1, Info[i][j] / 1000);
            }
            if (Ans[i][j] == '0') {
                AddEdge(Symbol[i][Record[i][j].first].second, RCnt + M * (i - 1) + j, 8);
                AddEdge(RCnt + M * (i - 1) + j, RCnt + N * M + Symbol[Record[i][j].second][j].first, 8, 0, i, j);
            }
        }
    }
}

int main(int argc, char *argv[]) {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    while (~scanf("%d%d", &N, &M)) {
        Init();
        mem(Info, 0);
        mem(Book, -1);
        mem(Ans, '_');
        Build();
        Dinic(0, RCnt + N * M + CCnt + 1);
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= M; ++j) {
                if (Book[i][j] != -1) {
                    Ans[i][j] = '0' + edges[Book[i][j]].Weight + 1;
                }
                else if (Ans[i][j] == '0') {
                    Ans[i][j]++;
                }
                printf("%c", Ans[i][j]);
                if (j != M) {
                    putchar(' ');
                }
            }
            putchar('\n');
        }
    }
#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    system("gedit out.txt");
#endif
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Tony5t4rk/article/details/81946839
今日推荐