luogu P1330 封锁阳光大学 二分图

//图是不一定联通的
//于是,我们就可以将整张图切分成许多分开的连同子图来处理 

//每一条边所连接的点中,至少要有一个被选中
//每一条边所连接的两个点,不能被同时选中
//所以:每一条边都有且仅有一个被它所连接的点被选中
//因为要处理的是一个连通图,所以,对于这一个图的点的选法,可以考虑到相邻的点染成不同的颜色
// 于是,对于一个连通图,要不就只有两种选法(因为可以全部选染成一种色的,
//也可以全部选染成另一种色的),要不就是impossible!

//所以,需要找到每一个子连通图,
//对它进行黑白染色,然后取两种染色中的最小值,然后最后汇总,就可以了。 

//另外,要判断impossible,只需要加一个used数组,
//记录已经遍历了哪些点。如果重复遍历一个点,且与上一次的颜色不同,
//则必然是impossible的。 
#include<cstdio>
#include<cstring>
#include<iostream> 
#include<algorithm>
#define ll long long
using namespace std;
const int N = 2e5+10;
int e[N],ne[N],h[N],idx;
bool used[N];
int color[N];
int sum[N];
int n,m;
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
bool dfs(int u,int col)
{
	if(used[u])
	{
		if(color[u]==col)
			return true;
		return false;
	}
	used[u]=1;
	color[u]=col;
	sum[col]++;
	bool f1=1;
	for(int i=h[u];i!=-1&&f1;i=ne[i])
		f1=f1&&dfs(e[i],1-col);
	return f1;
}
void solve()
{
	cin>>n>>m;
	memset(h,-1,sizeof h);
	while(m--)
	{
		int a,b;
		cin>>a>>b;
		add(a,b);
		add(b,a);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(used[i])
			continue;
		sum[0]=sum[1]=0;
		if(!dfs(i,0))
		{
			cout<<"Impossible"<<endl;
			return ;
		}
		ans+=min(sum[0],sum[1]);
	}
	cout<<ans<<endl;
}
int main()
{
	int t=1;
	while(t--)
		solve();
	return 0;
}
原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12882278.html