zoukankan      html  css  js  c++  java
  • P1330 封锁阳光大学[搜索+染色]

    题目来源:洛谷

    题目描述

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

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

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

    输入输出格式

    输入格式:

    第一行:两个整数N,M

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

    输出格式:

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

    输入输出样例

    输入样例#1: 
    3 3
    1 2
    1 3
    2 3
    
    输出样例#1: 
    Impossible
    
    输入样例#2:
    3 2
    1 2
    2 3
    
    输出样例#2: 
    1

    说明

    【数据规模】

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

    解析:

    这题质量很高,卡了我一天,最后也是有思路了,然而还是卡了几次没过,原来这题可能有不连通的子图。。。

    仔细研究题目之后,我们发现在这样一个无向图中,按照题目要求,每条边都要被占据。

    如果每条边都要被占据,那么这条边的两端点必然有一点占了一个河蟹。

    也就是说,一个无向图中,如果要满足题目条件,必须满足在每条边都被占据的情况下,每条边两端点上不能同时出现河蟹,但是其中有一点要有一只河蟹。

    题解里dalao管这思路叫染色,每条边两端不能出现相同颜色

    我们可以搜一遍整个图,记录每个点是否被染色,以及每种颜色的染色次数。

    因为这个颜色具体来说就代表着河蟹的位置,那么,每次搜索会得到两种颜色的解,也就是说河蟹以这两种方式放置是等价的,我们可以手模检验一下。

    我们只要取其中最小值就是河蟹的最小数量了。

    前面提到有不连通子图,这就很坑,我们每次搜索完的时候还要看看整个图是否全部被遍历到,否则就要在另一个子图中继续我们的搜索,并累加答案。

    参考代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<queue>
     5 #include<vector>
     6 #include<cstring>
     7 #define N 20010
     8 using namespace std;
     9 int head[N],tot,n,m;
    10 bool v[N*100],pr[N*100];
    11 int sum[2];
    12 struct node{
    13     int ver,next;
    14 }g[N*100];
    15 void add(int x,int y)
    16 {
    17     g[++tot].ver=y;
    18     g[tot].next=head[x],head[x]=tot;
    19 }
    20 
    21 bool dfs(int x,int color)
    22 {
    23     if(v[x]){
    24         //如果当前走到的点已被染色,判断它与上一个点构成的关系是否合法 
    25         if(pr[x]==color) return true;
    26         else return false;
    27     }
    28     v[x]=1;pr[x]=color;//记录染色状态 
    29     sum[color]++;//记录染色次数 
    30     bool k=1;//初始允许访问 
    31     for(int i=head[x];i&&k;i=g[i].next){//走下一步 
    32         int y=g[i].ver;
    33         k=k&&dfs(y,1-color);//能否访问下一个点? 
    34         //下一个点换一种颜色 
    35     }
    36     return k;
    37 }
    38 int main()
    39 {
    40     scanf("%d%d",&n,&m);
    41     for(int i=1;i<=m;i++)
    42     {
    43         int x,y;
    44         scanf("%d%d",&x,&y);
    45         add(x,y);add(y,x);
    46     }
    47     int ans=0;
    48     for(int i=1;i<=n;i++)
    49     {
    50         if(v[i]) continue;
    51         sum[0]=sum[1]=0;//发现子图,再次对子图染色 
    52         if(!dfs(i,0)){
    53             printf("Impossible
    ");return 0;
    54         }
    55         ans+=min(sum[0],sum[1]);//很巧妙一个地方,小的那一个一定是河蟹的数量 
    56     }
    57     printf("%d
    ",ans);
    58     return 0;
    59 }

    2019-05-29 19:25:54

  • 相关阅读:
    Asp中返回到前一页面
    vs2008 简单ajax 功能的实现。
    Arcgis Server的唯一值渲染
    ArcGIS Server中缓冲区分析的实现(点)
    用两个Calendar控件来控制数据库记录的读入
    把十进制转化为二进制的一种方法
    Segmentation fault (core dumped)
    libc glibc glib 的关系
    使用异或加密数据
    宏定义一些内容
  • 原文地址:https://www.cnblogs.com/DarkValkyrie/p/10945706.html
Copyright © 2011-2022 走看看