做题笔记 #5
小清新构造水题。
似乎题解区还没有像我这样找环然后拓扑排序的做法。也可能是我没看到。
题意
给定一个简单无向连通图,现在要你选一些边删去,使图不连通,而且没有孤立点。
分类讨论图中是否存在环:
一、存在环
发现不合法的情况只有三个点形成环的情况,也就是 \(n\) 和 \(m\) 都等于 \(3\)。
对于合法的情况,找到环中度数最小(指原图的度数)的点,再找到环上这个点所连的度数最小的点,把这两个点与环上其他的点的边删去(这句话有点拗口,多想想)。
这时候,这两个被选出来的点一定不是孤立点(因为已经有两个点了)。因为不是三个点构成的环,而且环上剩下的点又不是环中度数最小的点,那么剩下的点一定不是孤立点。所以该方案合法(本题关键)。
二、不存在环
说白了就是一颗树。
发现菊花图一定不合法。
如果不是菊花图,那么选一个非叶子节点。因为不是菊花图,所以可以找到一个和该点相连的非叶子节点。删除这两个点所连的边后,图就不连通啦!
怎么想到的:
一个直观的想法不管度数为 \(1\) 的点。可以把这些点删掉。一直重复这个过程,有点像拓扑排序。
那么最后一定会剩下一个环(也许因该叫点双?都无所谓啦~)。分讨一下发现可以做。
具体实现
找环直接用拓扑排序。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5;
inline int read() {
	int x = 0; bool f(0); char ch = getchar();
	while(!isdigit(ch)) f = ch == '-', ch = getchar();
	while(isdigit(ch)) x = (x<<1) + (x<<3) + (ch^48), ch = getchar();
	return f ? -x : x;
}
int n, m, du[N], cdu[N];
bitset < N > vis;
queue < int > q;
vector < int > edge[N], delu, delv;
void sub2() {
	for(int i = 1; i <= n; ++i) if(du[i] == 1) q.push(i),vis[i] = 1;
	while(!q.empty()) {
		int x = q.front(); q.pop();
		for(auto y : edge[x]) if(!vis[y]) {
			du[y] --;
			if(du[y] == 1) q.push(y), vis[y] = 1;
		}
	}
	int mn = 0, mv = 0;
	for(int i = 1; i <= n; ++i) if(!vis[i] && (!mn || cdu[i] < cdu[mn])) mn = i;
	for(auto v : edge[mn]) if(!vis[v]) {
		if(!mv || cdu[v] < cdu[mv]) mv = v;
	}
	for(auto v : edge[mn]) if(!vis[v] && v != mv) {
		delu.push_back(mn);
		delv.push_back(v);
	}
	for(auto v : edge[mv]) if(!vis[v] && v != mn) {
		delu.push_back(mv);
		delv.push_back(v);
	}
	printf("%d\n", (int)delu.size());
	for(int i = 0; i < (int)delu.size(); ++i) {
		printf("%d %d\n", delu[i], delv[i]);
	}
}
void sub1() {
	int mn = 0;
	for(int i = 1; i <= n; ++i) if(du[i] != 1) {
		mn = i;
		break;
	}
	for(int v : edge[mn]) if(du[v] != 1) {
		printf("1\n%d %d\n", mn, v);
		return ;
	}
	puts("-1");//菊花。 
}
int main() {
	n = read(), m = read(); 
	if(n == 3 && m == 3) {
		puts("-1");
		return 0;
	}
	for(int i = 1; i <= m; ++i) {
		int u = read(), v = read();
		cdu[u] ++, cdu[v] ++;
		du[u] ++, du[v] ++;
		edge[u].push_back(v);
		edge[v].push_back(u);
	}
	if(m == n - 1) sub1();
	else sub2();
	return 0;
}

                
            
        
浙公网安备 33010602011771号