J. Burnished Security Updates
题意:对于所给的图(不一定连通),选择一些点作为一个集合,满足每条边有且仅有一个端点为该集合的点,要求计算该集合大小的最小可能,若无法找到一个集合满足条件则输出 -1
思路:由「每条边有且仅有一个端点为该集合的点」的性质,联想到二分图(二部图) 的性质。采用判断二分图的染色算法,其中所用次数较少的颜色数,即为我们所需的结果,而对于不连通的图,则取每个连通部分所用次数较少的颜色数。若中途判断无法构成二分图,即说明找不到题目描述的集合,输出 -1
即可。
相关链接:
判断二分图 - LeetCode
#include<bits/stdc++.h>
using namespace std;const int N = 3e5+10;
vector<int> g[N];
int color[N];
int cnt_color[2];
bool dfs(int v, int c)
{if(color[v] != -1) return color[v] == c;color[v] = c; cnt_color[c]++;for(int i = 0; i < g[v].size(); i++){if(!dfs(g[v][i], !c)) return false;}return true;
}
int main()
{int n,m;cin>>n>>m;int v1,v2;for(int i = 0; i < m ; i++){scanf("%d%d",&v1,&v2);g[v1].push_back(v2);g[v2].push_back(v1);}for(int i = 1; i <= n; i++) color[i] = -1;int ans = 0;for(int i = 1; i <= n; i++){if(color[i] == -1){cnt_color[0] = cnt_color[1] = 0;if(!dfs(i,0)){ans = -1;break;}ans += min(cnt_color[0], cnt_color[1]);}}cout<<ans<<"\n";
}