洛谷 P1330 封锁阳光大学
【题目链接】
洛谷 P1330 封锁阳光大学
【题目考点】
1. 图论:二分图判定
【解题思路】
放河蟹可以抽象为选择顶点。
“当两只河蟹封锁了相邻的两个点时,他们会发生冲突”,也就是说不能选择一条边连接的两个顶点。
河蟹准备封锁所有道路,也就是说每条边两端的顶点至少有一个是被选择的顶点。不存在某条边两端都是未选择顶点。
对于一个图的连通分量,所有选择的顶点构成一个集合,未选择的顶点构成一个集合。图中每条边都连接了一个已选择顶点和未选择顶点,显然该图是二分图。
对每个连通分量进行二分图染色,染色的同时统计每个颜色顶点集合的顶点数量。染色后得到两种颜色的顶点集合。由于要选择最少的顶点,那么看哪一个集合的顶点数量更少,就选择哪个集合中的所有顶点。
将每个连通分量中顶点数更少的集合的顶点数加和,即为该题结果。如果某个连通分量在进行二分图判定后发现并不是二分图,那么输出Impossible。
【题解代码】
解法1:二分图判定
- 写法1:深搜二分染色
#include<bits/stdc++.h>
using namespace std;
#define N 10005
int n, m, color[N], ct[3], ans;//ct[1]、ct[2]颜色1的数量和颜色2的数量
vector<int> edge[N];
bool dfs(int u)
{
for(int v : edge[u])
{
if(color[v] == 0)
{
color[v] = 3-color[u];
ct[color[v]]++;
if(!dfs(v))
return false;
}
else if(color[v] == color[u])
return false;
}
return true;
}
int main()
{
int f, t;
cin >> n >> m;
for(int i = 1; i <= m; ++i)
{
cin >> f >> t;
edge[f].push_back(t);
edge[t].push_back(f);
}
for(int i = 1; i <= n; ++i) if(color[i] == 0)
{
color[i] = 1;
ct[1] = 1, ct[2] = 0;
if(!dfs(i))
{
cout << "Impossible" << endl;
return 0;
}
ans += min(ct[1], ct[2]);
}
cout << ans;
return 0;
}
- 写法2:广搜二分染色
#include<bits/stdc++.h>
using namespace std;
#define N 10005
int n, m, color[N], ct[3], ans;//ct[1]、ct[2]颜色1的数量和颜色2的数量
vector<int> edge[N];
bool bfs(int sv)
{
queue<int> que;
que.push(sv);
while(!que.empty())
{
int u = que.front();
que.pop();
for(int v : edge[u])
{
if(color[v] == 0)
{
color[v] = 3-color[u];
ct[color[v]]++;
que.push(v);
}
else if(color[v] == color[u])
return false;
}
}
return true;
}
int main()
{
int f, t;
cin >> n >> m;
for(int i = 1; i <= m; ++i)
{
cin >> f >> t;
edge[f].push_back(t);
edge[t].push_back(f);
}
for(int i = 1; i <= n; ++i) if(color[i] == 0)
{
color[i] = 1;
ct[1] = 1, ct[2] = 0;
if(!bfs(i))
{
cout << "Impossible" << endl;
return 0;
}
ans += min(ct[1], ct[2]);
}
cout << ans;
return 0;
}