题解:luogu.P1330 封锁阳光大学(图论配套精选专练)
题目:P1330 封锁阳光大学
题意建模
有给定一张图, 个点,
条边,能否将整张图二分。
算法分析
现在要求对若干条边进行染色即能否将整张图二分。这是二分图的常见处理方法。怎样染色?定义状态 ,表示在当前状态下,是哪一个节点(
);又是哪一种颜色(
)。那么现在就很明显,对整张图进行遍历,这里可以选用深度优先(
),也可以选用广度优先(
)。我们给出前者的 CODE 如下:
参考程序
//luogu.P1330.DFS实现
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
using namespace std;
const int N=1e4+5,M=1e5+5;
vector <int> e[M];//vector存边
int mark[M];
int n,m,ans,cnt,c[N];//c[]记录所有节点的颜色
void dfs(int node,int col)//定义状态,当前节点编号及其颜色
{
if(c[node]!=-1 && c[node]!=col) {cout<<"Impossible"<<endl; exit(0);}
if(c[node]==col) return;
mark[node]=1,c[node]=col,cnt++;//cnt是总共的染色数
for(int i=0;i<e[node].size();i++) dfs(e[node][i],col^1);//双色染,每次异或1
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
memset(mark,0,sizeof(mark));
for(int i=1;i<=n;i++)
if(!mark[i])
{
memset(c,-1,sizeof(c));//初始化c[]为-1,后续只有两种颜色:0-1
cnt=0;
dfs(i,0);
int sum=0;
for(int i=1;i<=n;i++) sum+=c[i]==1;//初始是0,染一次变成1,所以这一类染的次数等于(1)河蟹的个数
ans+=min(sum,cnt-sum);//将染成1的数量与染成0的数量取min并加在ans上
}
cout<<ans<<endl;
return 0;
}
细节研讨
- 注意染色的顺序和意义
- 每次进入下一个节点时都要异或1,表示不同的联通块

浙公网安备 33010602011771号