HDU 3338 Kakuro Extension

网络最大流

TLE了两天的题目。80次Submit才AC,发现是刘汝佳白书的Dinic代码还可以优化。。。。。瞬间无语。。。。。

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;

const int maxn = 30000 + 10;
const int INF = 0x7FFFFFFF;
struct Edge
{
    int from, to, cap, flow;
    Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
};
vector<Edge>edges;
vector<int>G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
int n, m, s, t;

void init()
{
    for (int i = 0; i < maxn; i++)
        G[i].clear();
    edges.clear();
}
void AddEdge(int from, int to, int cap)
{
    edges.push_back(Edge(from, to, cap, 0));
    edges.push_back(Edge(to, from, 0, 0));
    int w = edges.size();
    G[from].push_back(w - 2);
    G[to].push_back(w - 1);
}
bool BFS()
{
    memset(vis, 0, sizeof(vis));
    queue<int>Q;
    Q.push(s);
    d[s] = 0;
    vis[s] = 1;
    while (!Q.empty())
    {
        int x = Q.front();
        Q.pop();
        for (int i = 0; i<G[x].size(); i++)
        {
            Edge e = edges[G[x][i]];
            if (!vis[e.to] && e.cap>e.flow)
            {
                vis[e.to] = 1;
                d[e.to] = d[x] + 1;
                Q.push(e.to);
            }
        }
    }
    return vis[t];
}
int DFS(int x, int a)
{
    if (x == t || a == 0)
        return a;
    int flow = 0, f;
    for (int &i = cur[x]; i<G[x].size(); i++)
    {
        Edge e = edges[G[x][i]];
        if (d[x]+1 == d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
        {
            edges[G[x][i]].flow+=f;
            edges[G[x][i] ^ 1].flow-=f;
            flow+=f;
            a-=f;
            if(a==0) break;
        }
    }
    if(!flow) d[x] = -1;
    return flow;
}
int dinic(int s, int t)
{
    int flow = 0;
    while (BFS())
    {
        memset(cur, 0, sizeof(cur));
        flow += DFS(s, INF);
    }
    return flow;
}

//输入输出
int N, M;
char S[1000];
int Map1[105][105];//横向
int Map2[105][105];//纵向
int BH[105][105];
int FLAG[maxn];

int main()
{
    while (~scanf("%d%d", &N, &M))
    {

        edges.clear();
        for (int i = 0; i<maxn; i++) G[i].clear();
        memset(Map1, 0, sizeof(Map1));
        memset(Map2, 0, sizeof(Map2));
        memset(BH, 0, sizeof(BH));
        for (int i = 1; i <= N; i++)
            for (int j = 1; j <= M; j++)
            {
                scanf("%s", S);
                if (S[3] == ‘.‘) continue;
                if (S[3] == ‘X‘) Map1[i][j] = -1, Map2[i][j] = -1;
                else
                {
                    if (S[2] == ‘X‘)
                    {
                        Map2[i][j] = -1;
                        Map1[i][j] = (S[4] - ‘0‘) * 100 + (S[5] - ‘0‘) * 10 + (S[6] - ‘0‘) * 1;
                    }
                    else if (S[4] == ‘X‘)
                    {
                        Map1[i][j] = -1;
                        Map2[i][j] = (S[0] - ‘0‘) * 100 + (S[1] - ‘0‘) * 10 + (S[2] - ‘0‘) * 1;
                    }
                    else
                    {
                        Map1[i][j] = (S[4] - ‘0‘) * 100 + (S[5] - ‘0‘) * 10 + (S[6] - ‘0‘) * 1;
                        Map2[i][j] = (S[0] - ‘0‘) * 100 + (S[1] - ‘0‘) * 10 + (S[2] - ‘0‘) * 1;
                    }
                }
            }
        int Tot = 1;
        for (int i = 1; i <= N; i++)
            for (int j = 1; j <= M; j++)
                if (Map1[i][j] == 0)
                    BH[i][j] = Tot, Tot++;
        int Duan = Tot - 1;//方格编号1--Duan
        s = 0;
        t = 30000;
        for (int i = 1; i <= N; i++)
            for (int j = 1; j <= M; j++)
            {
                if (Map1[i][j] != -1 && Map1[i][j] != 0)
                {
                    int Zong = 0;
                    for (int k = j + 1;; k++)
                    {
                        if (k>M || Map1[i][k] != 0) break;
                        AddEdge(Tot, BH[i][k], 8);
                        Zong++;
                    }
                    AddEdge(s, Tot, Map1[i][j] - Zong);
                    Tot++;
                }
            }
        for (int i = 1; i <= N; i++)
            for (int j = 1; j <= M; j++)
            {
                if (Map2[i][j] != -1 && Map2[i][j] != 0)
                {
                    int Zong = 0;
                    for (int k = i + 1;; k++)
                    {
                        if (Map2[k][j] != 0 || k>N) break;
                        AddEdge(BH[k][j], Tot, 8);
                        Zong++;
                    }
                    AddEdge(Tot, t, Map2[i][j] - Zong);
                    Tot++;
                }
            }
        dinic(s, t);
        memset(FLAG, 0, sizeof FLAG);
        for (int i = 0; i<edges.size(); i = i + 2)
            if (edges[i].from >= 1 && edges[i].from <= Duan)
                FLAG[edges[i].from] = edges[i].flow;
        for (int i = 1; i <= N; i++)
        {
            for (int j = 1; j <= M; j++)
            {
                if (BH[i][j] == 0) printf("_");
                else printf("%d", FLAG[BH[i][j]] + 1);
                if (j<M) printf(" ");
            }
            printf("\n");
        }
    }
    return 0;
}
时间: 2024-08-29 07:42:47

HDU 3338 Kakuro Extension的相关文章

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

HDU 3338 Kakuro Extension(网络流)

HDU 3338 Kakuro Extension 题目链接 题意:完成如图的游戏,填充数字1-9 思路:网络流的行列模型,把每行每列连续的一段拆分出来建图即可,然后题目有限制一个下限1,所以 每行每列的容量减去相应的数字,然后建图建容量8就好,这样就默认原来容量已经有1了 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespac

HDU - 3338 Kakuro Extension(最大流)

题目大意:看一下图基本就知道了 解题思路:难点是构图.. 设置一个超级源点和所有的行的和相连,容量为该行的和 - 该行和由几个数相加得到 设置一个超级汇点,和所有列的和相连,容量为该列的和 - 该列和由几个数相加得到 接着就是空白部分和 "行和"和 "列和"的关系了 空白连向该行的行和,权值为8 空白连向该列的列和,权值也为8 为什么为8,而不是9,因为流量也可能为0,但是0是不能填的,所以将容量设为8,最后取值的时候加1即可 #include <cstdio

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

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

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 最大流 ****

题意: 黑格子右上代表该行的和,左下代表该列下的和 链接:点我 这题可以用网络流做.以空白格为节点,假设流是从左流入,从上流出的,流入的容量为行和,流出来容量为列和,其余容量不变.求满足的最大流.由于流量有上下限限制,可以给每个数都减掉1,则填出来的数字范围为0—8, 就可以用单纯的网络流搞定了.求出来再加上就可以了. 这一题主要是在建图 建图: 一共有四类点: 1. 构造源点ST,汇点ED 2. 有行和的格子,即\上面有值的格子,此类节点设为A 3. 空白格,设为B 4. 有列和的格子,即\下

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

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

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

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