封锁阳光大学
题目描述
曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。
阳光大学的校园是一张由N个点构成的无向图,N个点之间由M条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在与这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。
询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。
输入输出格式
输入格式:
第一行:两个整数N,M
接下来M行:每行两个整数A,B,表示点A到点B之间有道路相连。
输出格式:
仅一行:如果河蟹无法封锁所有道路,则输出“Impossible”,否则输出一个整数,表示最少需要多少只河蟹。
输入输出样例
说明
【数据规模】
1<=N<=10000,1<=M<=100000,任意两点之间最多有一条道路。
分析:
思路非常巧妙的一道图论题,也是理解染色问题的一道好题。
首先,题目并没有保证是一个连通图,但经过分析也可以知道,只要每个子连通图都满足要求即可。重点在于,题目要求每一条边的连个端点必须有且仅有一个端点被占。那么实际上也就等效于,任意两个相邻的点必须被染成不同的颜色。那么思路有了就好做了,直接深搜或者广搜都行,遍历每个子连通图判断是否可以按照该原则染色即可。具体看代码。
Code:
1 //It is made by HolseLee on 9th June 2018 2 //Luogu.org P1330 3 #include<bits/stdc++.h> 4 using namespace std; 5 const int N=1e4+7; 6 const int M=1e5+7; 7 bool vis[N]; 8 int n,m,head[N],size,col[N],sum[2],ans; 9 struct Node{int to,next;}edge[M<<1]; 10 inline int read() 11 { 12 char ch=getchar();int num=0;bool flag=false; 13 while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();} 14 while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();} 15 return flag?-num:num; 16 } 17 inline void add(int x,int y) 18 { 19 edge[++size].to=y; 20 edge[size].next=head[x]; 21 head[x]=size; 22 } 23 inline bool dfs(int u,int color) 24 { 25 if(vis[u]){ 26 if(col[u]==color)return true; 27 return false;} 28 vis[u]=true;sum[col[u]=color]++; 29 bool flag=true; 30 for(int i=head[u];i!=-1;i=edge[i].next){ 31 flag=flag&&dfs(edge[i].to,1-color);} 32 return flag; 33 } 34 int main() 35 { 36 memset(head,-1,sizeof(head)); 37 memset(vis,false,sizeof(vis)); 38 n=read();m=read();int x,y; 39 for(int i=1;i<=m;i++){ 40 x=read();y=read(); 41 add(x,y);add(y,x);} 42 for(int i=1;i<=n;i++){ 43 if(vis[i])continue; 44 sum[0]=sum[1]=0; 45 if(!dfs(i,0)){ 46 printf("Impossible"); 47 return 0;} 48 ans+=min(sum[0],sum[1]);} 49 printf("%d",ans); 50 return 0; 51 }