zoukankan      html  css  js  c++  java
  • 概述「并查集补集转化」模型&&luoguP1330 封锁阳光大学

    奇妙的模型转化以及并查集思想

    模型概述

    有图$G=(V,E)$,初始所有点为白色,现在要将其中一些点染为黑色,要求染色后满足:$∀(u,v)∈E$,$∃col_u!=col_v$。求最小染色点数。

    题目描述

    曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。

    阳光大学的校园是一张由N个点构成的无向图,N个点之间由M条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在与这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。

    询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。

    输入输出格式

    输入格式:

    第一行:两个整数N,M

    接下来M行:每行两个整数A,B,表示点A到点B之间有道路相连。 

    输出格式:

    仅一行:如果河蟹无法封锁所有道路,则输出“Impossible”,否则输出一个整数,表示最少需要多少只河蟹。

    说明

    【数据规模】

    1<=N<=10000,1<=M<=100000,任意两点之间最多有一条道路。


    题目分析

    本来想写道图论题的,但看题解时候看到一篇并查集的题解感觉非常奇妙……

    常规做法

    大力搜索?黑白染色?好像无向图缩环之类的在这道题没什么用。

    dp也无能为力,因为虽说和树形dp那里独立集全覆盖有些相像,但是这题是图的形式,有环的约束,也不能简单地缩点。

    奇妙的并查集

    观察一下要求:

    1. 所有道路都要求被覆盖
    2. 选取满足要求的独立集

    诶,那么就是说“敌人的敌人就是我的朋友”咯?

    这不就成了[BOI2003]团伙那道题吗?

    回顾一下那题,我们可以用$enemy[x]$表示所有$x$的敌人。这种思想可以快速合并不在一个集合内的元素,而且非常巧妙!

    姑且就称为补集转化的思想吧。这里是以前写的团伙的博客

    (感觉好像有那么一点像2-sat???)

     1 #include<bits/stdc++.h>
     2 const int maxn = 10035;
     3 
     4 int sum[maxn],fa[maxn],enemy[maxn];
     5 int n,m,ans;
     6 bool vis[maxn];
     7 
     8 int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
     9 void unions(int x, int y)
    10 {
    11     int fx = get(x), fy = get(y);
    12     fa[fx] = fy, sum[fy] += sum[fx], sum[fx] = 0;
    13 }
    14 int main()
    15 {
    16     scanf("%d%d",&n,&m);
    17     for (int i=1; i<=n; i++) fa[i] = i, sum[i] = 1;
    18     for (int i=1; i<=m; i++)
    19     {
    20         int a,b,fa,fb;
    21         scanf("%d%d",&a,&b);
    22         fa = get(a), fb = get(b);
    23         if (fa!=fb){
    24             if (enemy[a]) unions(enemy[a], fb);
    25             if (enemy[b]) unions(enemy[b], fa);
    26             enemy[a] = fb, enemy[b] = fa;
    27         }
    28         else{
    29             puts("Impossible");
    30             return 0;
    31         }
    32     }
    33     for (int i=1; i<=n; i++)
    34     {
    35         int x = get(i);
    36         if (!vis[x]){
    37             int y = get(enemy[x]);
    38             ans += std::min(sum[x], sum[y]);
    39             vis[x] = vis[y] = 1;
    40         }
    41     }
    42     printf("%d
    ",ans);
    43     return 0;
    44 }

    END

  • 相关阅读:
    【数据结构】线性表&&顺序表详解和代码实例
    【智能算法】超详细的遗传算法(Genetic Algorithm)解析和TSP求解代码详解
    【智能算法】用模拟退火(SA, Simulated Annealing)算法解决旅行商问题 (TSP, Traveling Salesman Problem)
    【智能算法】迭代局部搜索(Iterated Local Search, ILS)详解
    10. js时间格式转换
    2. 解决svn working copy locked问题
    1. easyui tree 初始化的两种方式
    10. js截取最后一个斜杠后面的字符串
    2. apache整合tomcat部署集群
    1. apache如何启动
  • 原文地址:https://www.cnblogs.com/antiquality/p/9262282.html
Copyright © 2011-2022 走看看