#include using namespace std; const int N = 1e4 + 10; //题目中说结点数最大10^4=1e4 const int M = 1e5 * 2 + 10; //边数上限,因为是无向图,所以记录两次,就是1e5*2 /* 根据题意可知二分图染色。若无法被染成二分图,输出Impossible; 反之,对于每个二分图,记录两种颜色的点的个数,取min后记录答案中。 注意,图可能不连通。因此对于每个二分图,都要进行取min操作,而不是对整个图染色后取min。 */ int color[N]; //0:未上色,1:黑色,2:白色 int n, m, ans; //广度优先搜索的队列 queue q; //链式前向星 struct Edge { int to, next; } edge[M]; int idx, head[N]; void add(int u, int v) { edge[++idx].to = v; edge[idx].next = head[u]; head[u] = idx; } //广度优先搜索 int bfs(int a) { int ans1 = 1, ans2 = 0; color[a] = 1;//假设用颜色1着了色 q.push(a); while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].to; //目标点未着色 if (color[v] == 0) { //来源点是黑的,那么目标点是白的 if (color[u] == 1) color[v] = 2, ans2++; //来源点是白的,那么目标点是黑的 else if (color[u] == 2) color[v] = 1, ans1++; q.push(v); } else //如果已着色,那么需要判断和现在的要求是不是有冲突: if (color[v] == color[u]) {//相临的存在冲突 printf("Impossible"); exit(0); } } } //哪个小就用哪个 return min(ans1, ans2); } int main() { //n个结点,m条边 cin >> n >> m; //m条边 for (int i = 1; i <= m; ++i) { int x, y; cin >> x >> y; add(x, y), add(y, x); //无向图双向建边,题目中明显说是无向图! } //注意,图可能不连通。因此对于每个二分图,都要进行取min操作, //而不是对整个图染色后取min。 //这里有一个小技巧,就是遍历每个结点,如果此结点没有上过色,就表示是一个独立的图,需要单独计算 for (int i = 1; i <= n; ++i) if (!color[i]) ans += bfs(i); //输出 printf("%d", ans); return 0; }