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\n");return 0;
54         }
55         ans+=min(sum[0],sum[1]);//很巧妙一个地方,小的那一个一定是河蟹的数量 
56     }
57     printf("%d\n",ans);
58     return 0;
59 }

2019-05-29 19:25:54

posted @ 2019-05-29 19:26  DarkValkyrie  阅读(744)  评论(0编辑  收藏  举报