首页 > 其他分享 >Flood Fill

Flood Fill

时间:2023-12-06 21:35:31浏览次数:27  
标签:std 1100000 int value Flood Fill now 翻转

好习惯:先看样例,直接手模。

手摸完第一个样例我们会发现:

当两个值不一样的连通块相邻时,我们若翻转其中一个,再翻转另外一个的时候,与直接翻转另外一个没有区别。

举个例子:010

我们先翻转 1,变成了 000,此时我们再翻转 000 则变成了 111

与直接翻转 010 两边的 0 变成 111 没有任何区别。

所以我们大胆猜测将一个连通块变为一个点。

所以知道我们在选择翻转一个连通块的时候不用翻转周围的连通块。

所以显然我们能只翻一个或者都不翻。

问题来了,我们该怎么处理这个???

请看下图:

其中 0 的点表示数值为 0 的连通块,1 的点同理。边上的 翻转 表示连通块翻转的话会造成的花费(也就是翻转后 A 图与 B 图不同的点的个数), 不翻转 同理。

这样就能保证我们的最小割的容量不存在同时翻转的贡献了。

#include <bits/stdc++.h>

int N, M;
int S = 1, T = 2;
int tot = 2, id[1100][1100];
int A[1100][1100], B[1100][1100];
int cnt = 1, head[1100000], next[2100000], to[2100000], value[2100000];

void AddEdge(int u, int v, int val) {
    ++ cnt;
    next[cnt] = head[u];
    head[u] = cnt;
    to[cnt] = v;
    value[cnt] = val;
}

class DisjointSet {
public:
    int fat[1100000];
    int size[1100000];
    int different[1100000]    ;
    void clear() {
        for (int i = 1; i <= N * M + 100; ++ i) {
            fat[i] = i;
            size[i] = 1;
            different[i] = 0;
        }
    }
    int Find(int x) {
        if (fat[x] != x)
            fat[x] = Find(fat[x]);
        return fat[x];
    }
    void Union(int x, int y) {
        x = Find(x);
        y = Find(y);
        if (x != y) {
            fat[x] = y;
            size[y] += size[x];
            different[y] += different[x];
        }
    }
    void Add(int x) {
        x = Find(x);
        different[x] ++;
    }
}set;

std::pair<int, int> origin[1100000];
std::set<std::pair<int, int>> Set;
bool visit[1100000];
int answer;

namespace Dinic {
    int deep[1100000], cur[1100000];
    void clear() {
        for (int i = 1; i <= tot; ++ i) {
            deep[i] = 0;
            cur[i] = head[i];
        }
    }
    bool Bfs(int begin, int end) {
        clear();
        deep[begin] = 1;
        std::queue<int> queue;
        queue.emplace(begin);
        while (queue.size()) {
            int now = queue.front();
            queue.pop();
            for (int i = head[now]; i; i = next[i]) {
                if (!value[i] || deep[to[i]])
                    continue;
                deep[to[i]] = deep[now] + 1;
                if (to[i] == end)
                    return true;
                queue.emplace(to[i]);
            }
        }
        return false;
    }
    int Dfs(int now, int end, int flow) {
        if (now == end)
            return flow;
        int rest = flow, temp;
        for (int i = cur[now]; i && rest; i = next[i]) {
            cur[now] = i;
            if (value[i] && deep[to[i]] == deep[now] + 1) {
                temp = Dfs(to[i], end, std::min(rest, value[i]));
                if (!temp)
                    deep[to[i]] = 0;
                value[i] -= temp;
                value[i ^ 1] += temp;
                rest -= temp;
            }
        }
        return flow - rest;
    }
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    std::cin >> N >> M;
    set.clear();
    memset(A, -1, sizeof(A));
    for (int i = 1; i <= N; ++ i) {
        for (int j = 1; j <= M; ++ j) {
            char ch;
            std::cin >> ch;
            A[i][j] = ch - '0';
            id[i][j] = ++ tot;
        }
    }
    for (int i = 1; i <= N; ++ i) {
        for (int j = 1; j <= M; ++ j) {
            char ch;
            std::cin >> ch;
            B[i][j] = ch - '0';
            if (A[i][j] != B[i][j]) 
                set.Add(id[i][j]);
            if (A[i][j] == A[i - 1][j]) 
                set.Union(id[i][j], id[i - 1][j]);
            if (A[i][j] == A[i][j - 1])
                set.Union(id[i][j], id[i][j - 1]);
        }
    }
    for (int i = 1; i <= N; ++ i) {
        for (int j = 1; j <= M; ++ j) {
            int now = set.Find(id[i][j]);
            int different = set.different[now];
            int same = set.size[now] - set.different[now];
            if (!visit[now]) {
                visit[now] = true;
                if (A[i][j] == 0) {
                    AddEdge(S, now, different);
                    AddEdge(now, S, 0);
                    AddEdge(now, T, same);
                    AddEdge(T, now, 0);
                }
                else {
                    AddEdge(S, now, same);
                    AddEdge(now, S, 0);
                    AddEdge(now, T, different);
                    AddEdge(T, now, 0);
                }
            }

            if (A[i][j] + A[i - 1][j] == 1) {
                int x = set.Find(id[i][j]);
                int y = set.Find(id[i - 1][j]);
                if (A[i][j] == 0)
                    Set.emplace(x, y);
                else
                    Set.emplace(y, x);
            }
            if (A[i][j] + A[i][j - 1] == 1) {
                int x = set.Find(id[i][j]);
                int y = set.Find(id[i][j - 1]);
                if (A[i][j] == 0)
                    Set.emplace(x, y);
                else
                    Set.emplace(y, x);
            }
        }
    }
    for (const std::pair<int, int> &iter: Set) {
        AddEdge(iter.first, iter.second, 1e9);
        AddEdge(iter.second, iter.first, 0);
    }
    while (Dinic::Bfs(S, T))
        answer += Dinic::Dfs(S, T, 1e9);
    std::cout << answer << '\n';
    return 0;
}

标签:std,1100000,int,value,Flood,Fill,now,翻转
From: https://www.cnblogs.com/jueqingfeng/p/17880572.html

相关文章

  • DataAdapter的Fill方法的连接是否会自动关闭的测试
    关于vs2005中dataadapter的fill方法的连接是否会自动关闭的测试此示例中所示的代码不显式打开和关闭Connection。如果Fill方法发现连接尚未打开,它将隐式地打开DataAdapter正在使用的Connection。如果Fill已打开连接,它还将在Fill完成时关闭连接。当处理单一操作(如Fill或......
  • Error: Component series.liquidFill not exists. Load it first.
    Error:Componentseries.liquidFillnotexists.Loaditfirst. 场景:使用水球图时,报错:Error:Componentseries.liquidFillnotexists.Loaditfirst.解决办法:1、先检查是否安装了echarts和echarts-liquidfill(注:echarts4.+的版本对应echarts-liquidfill2.+的版本)npmin......
  • IOI 2007 Flood
    有一些墙壁链接(ax,ay),(bx,by)每次若有墙壁的两边一个有水,一个为空,墙壁就破了然后水开始充了起来找出最后还存在的墙壁 首先我们可以看出来墙壁的两边是可以用节点表示的我们需要合并一些区间什么的,听说这一题有些人利用对偶图来求但是我不会可以自己想想怎么样合并/哪......
  • setBorderPainted(),setContentAreaFilled()
    去除按钮的边框当鼠标移到按钮时最外层的边框不显示setBorderPainted去除按钮的背景setBorderPainted......
  • 解决self.draw.draw_rectangle(xy, fill, 1) ValueError: y1 must be greater tha
    我尝试了很多方法,包括单不限于改labelme文件的直接报错,修改pillow包的原文件尝试注释掉raise的地方。最后都以失败告终。还有尝试重新安装最新版的包,来解决。最后经过多次尝试后发现,发生错误的地方的文件是有问题的,至于是什么问题到现在也不知道,那就删除最后停止位置时......
  • pgsql create table,cpp fill psql table via the third party library pqxx
    //createtablet1;createtablet1(idbigserialnotnullprimarykey,authorvarchar(40)notnull,commentvarchar(40)notnull,contentvarchar(40)notnull,headervarchar(40)notnull,isbnvarchar(40)notnull,objectvarchar(40)notnull,summaryvarchar(40......
  • Codeforces Round 633 (Div. 2) A. Filling Diamonds
    给定一个正整数\(n\),询问有多少种方式填充满图中\(4n-2\)的图。你可以使用的菱形:竖着摆放和横着摆放都是一种方案。显然选择某个位置竖着摆放,其他所有地方只能横着摆放,这样的位置有\(n\)个。具体图形见:https://codeforces.com/problemset/problem/1339/Aview#includ......
  • 泛型算法(find、count、sort、fill、unique、copy、lambda、迭代器)
    一、概述algorithm中,还有一些数值泛型算法定义在头文件numeric中。算法永远不会执行容器的操作)。1、find和count:#include<iostream>#include<algorithm>#include<numeric>#include<vector>#include<list>usingnamespacestd;usingv_int=vector<int>;usingv_s......
  • Java Arrays.fill() 方法详解
    在Java编程中,数组是一个非常常见的数据结构,而Java提供了许多有用的数组操作方法来简化开发过程。其中之一是Arrays.fill()方法,它允许我们填充一个数组的所有元素,将它们设置为指定的值。在本篇文章中,我们将深入探讨Arrays.fill()方法的用法、参数和示例,以帮助您更好地理解和使用它。......
  • CF1869C Fill in the Matrix
    Link首先想一下,如果又一列的\(MEX\)是\(n\)会有什么样的要求?需要这一样有\(0~n-1\)的所有数字并且没有\(n\)当我们知道这一点以后问题就很好解决了.我们应该构造数列的时候,满足第一行的\(MEX\)为\(0\),第\(i\)行的\(MEX\)为\(i-1\),这样就可以达到最大的答案。当\(......