题意: 判断能否将所有彼此了解的人分开,分成两组。如果可以还要输出最大匹配。
题解: 首先判断给出的条件是否为二分图,染色呗,写为代码就是一种颜色记为1,另一种颜色记为-1,若染色过程中发现两个相邻的点同色,则不能构成二分图,输出No
。如果能构成二分图,再用匈牙利算法计算最大匹配。
具体思路参考代码中注释。
代码一
这段代码的染色其实不太严谨,读者可以自己思考一下,但是应该是测试数据的原因,这样写也能过。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int n, m;
int match[210], vis[210];
int group[210];
vector<int> g[210];
bool dfs(int x){ //匈牙利算法计算最大匹配
for (int i = 0; i < g[x].size(); i++)
if(!vis[g[x][i]]){
vis[g[x][i]] = 1;
if(!match[g[x][i]] || dfs(match[g[x][i]])){
match[g[x][i]] = x; return true;
}
}
return false;
}
int main(){
while (cin >> n >> m){
for (int i = 0; i < 210; i++) g[i].clear();
memset(match, 0, sizeof match);
memset(group, 0, sizeof group);
int flag = 0;
for (int i = 0; i < m; i++){
int a, b;
cin >> a >> b;
if(group[a]){ //如果端点a已染色
if(group[a] == group[b])//两端点同色,flag标记不能构成二分图
flag = 1;
group[b] = 3 - group[a];//否则给另一端点标色(1或2)
}else if(group[b]) //a未染色,b已染色
group[a] = 3 - group[b];
else //均未染色,默认给a染色为1,给b染色为2.
//我认为不严谨的地方就在这,他没有像代码二一样递归判断如此染色是否合法。
//事实上这样的染色我用到另一个题目里就错了。这里应该是测试数据的原因侥幸通过了。
group[a] = 1, group[b] = 2;
g[a].push_back(b);
g[b].push_back(a);
}
if(flag) cout << "No" << endl;
else{
int sum = 0;
for (int i = 1; i <= n; i++){
memset(vis, 0, sizeof vis);
if(group[i]==1)
if(dfs(i))
sum++;
}
cout << sum << endl;
}
}
return 0;
}
代码二
这段代码中用了一个结构类似匈牙利算法的染色函数,
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int n, m, a, b;
int vis[205];
int match[205];
int color[205];
vector<int> g[205];
bool check(int u, int c){ //u为端点编号,c为颜色(1或-1)
color[u] = c; //染色
for (int i = 0; i < g[u].size(); i++){
int v = g[u][i]; /另一端点编号
if(color[v] == c) return false; //两端点同色则不能构成二分图
if(!color[v] && !check(v, -c)) return false; //另一端点未染色,但是染上-c之后依然不能构成二分图
}
return true;
}
bool dfs(int x){ //匈牙利算法求最大匹配
for (int i = 0; i < g[x].size(); i++){
int v = g[x][i];
if(!vis[v]){
vis[v] = 1;
if(!match[v] || dfs(match[v])){
match[v] = x;return true;
}
}
}
return false;
}
int main(){
while(~scanf("%d%d", &n, &m)){
for (int i = 0; i < 210; i++) g[i].clear();
memset(match, 0, sizeof match);
memset(color, 0, sizeof color);
while(m--){
scanf("%d%d", &a, &b);
g[a].push_back(b);
g[b].push_back(a);
}
int flag = 1;
for (int i = 1; i <= n; i++)
if(!color[i])
if(!check(i, 1)){
printf("No\n");
flag = 0;break;
}
if(flag){
int sum = 0;
for (int i = 1; i <= n; i++){
memset(vis, 0, sizeof vis);
if(color[i]==1)
if(dfs(i))
sum++;
}
printf("%d\n", sum);
}
}
return 0;
}