更新一下, 这道题就是双色染色问题(原谅我这么叫他)
洛谷P1330封锁阳光大学
题目描述
曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。
阳光大学的校园是一张由N个点构成的无向图,N个点之间由M条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在与这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。
询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。
输入输出格式
输入格式:
第一行:两个整数N,M
接下来M行:每行两个整数A,B,表示点A到点B之间有道路相连。
输出格式:
仅一行:如果河蟹无法封锁所有道路,则输出“Impossible”,否则输出一个整数,表示最少需要多少只河蟹。
input:
3 3
1 2
1 3
2 3
output:
Impossible
1.第一反应是这是一道图染色问题,因为相邻两个点有冲突,但分析发现不是(或者说不这么裸的是).
2.难道是模拟每一个结点开始进行遍历,看最后结果哪个更少是哪个? 不太可能,数据太大了.
3.想到一种方法:把一张图按照bfs分奇数层和偶数层,看哪个层点数最少,结果就是哪个. 如果同一层之间有点相连那么就Impossible. 发现可能是对的?
4.感觉像是从一张图中找出一棵生成树, 这棵树的层数是最小的.
综上所述:
相邻两个点之间一定有一个是有河蟹的,因为会有一条边. 那么就有两种状态: 染色或者不染色,那么用bfs分层,一层黑一层白,哪种层点少就选哪层,同一层邻边的Impossible. 一句话(我创的):黑白互斥层染色问题.
如何解决同一层的点之间有边的情况?
记录层次,发现从一个点扩展过来的点已经有层次了而且是和自己一个层,其实只有三种,上一层这一层下一层
上一层跳过,这一层Impossible(中途返回),下一层push,就ok了,回国头来统计黑白层点数量.
因为会比较层次,所以不像传统的遍历是建立visit数组,而是建立层数数组,以便互斥分析和结果统计.
结果只有40分. 似乎是这张图不一定是连通图, 所以要增加处理
这是个问题: 我有好多次都没有考虑图的联通性,以后一定要注意.
结果还是40分, 之前对的又有错了,之前错了又有对的.怎么会这样.
原因是重复判断了之前找过的点,加个vis数组去重.
然而现在是50分,该不会是思路出了问题吧.
妥协了,去看题解学习学习.
看题解发现思路差不多的,于是返回,找到了一个很明显的bug.原来是我之前移到多连通图时有几行代码要修改,但是我漏掉了一个地方, 所以出错了.
OK, 不完美地结束了. 经过思考对思维还是有一定地训练的.
最后贴代码
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 10005;
int n, m;
vector<int> G[maxn]; // 邻接表存储.
int layers[maxn] = {}; // 初始都是-1层
bool vis[maxn] = {};
bool bfs(int i)
{
queue<int> que;
que.push(i);
layers[i] = 1;
while (!que.empty()) {
int u = que.front();
que.pop();
for (int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if (layers[v] == layers[u] - 1) continue; // 遍历到了上一层,分过层了continue
if (layers[v] == layers[u]) return false; // 遍历到了同一层
layers[v] = layers[u] + 1; // 下一层那就加上去.
que.push(v);
}
}
return true;
}
int main()
{
memset(layers, -1, sizeof(layers));
cin >> n >> m;
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
int ans = 0;
for (int i = 1; i <= n; ++i) {
if (layers[i] == -1) {
//cout << "i = " << i << endl;
if (!bfs(i)) {
cout << "Impossible";
return 0;
} else {
int odd = 0, even = 0;
for (int i = 1; i <= n; ++i) {
if (layers[i] + 1 && !vis[i]) {
vis[i] = true;
if (layers[i] & 1) odd++;
else even++;
}
}
//cout << min(even, odd) << endl;
ans += min(even, odd);
}
}
}
cout << ans;
}
/*
3 3
1 2
1 3
2 3
3 2
1 2
2 3
6 6
1 2
2 3
3 4
1 4
4 5
5 6
*/