代码注释思路说明,简单绿题调试良久
查看原帖
代码注释思路说明,简单绿题调试良久
549521
boy♂Next♂dooor楼主2024/10/11 22:11

思路:与https://www.bilibili.com/video/BV1SC4y1m7zD/?spm_id_from=333.337.search-card.all.click&vd_source=c42ae4e60815003575acd88813c316f6 以及那个二分图做法的题解 类似

确定了T/F/U的连通块只要有U全是U;不确定的连通块不是二分图(矛盾)就全是U

#include<bits/stdc++.h>
#define add(x,y,w) g[x].push_back({y,w})
#define int long long
using namespace std;
typedef long long ll;
const int N = 1e5+5;
struct Edge {
	int v, w;//w: 0- 1+
};
int n, m, C, t;
vector<Edge> g[N];
int ans, cnt, color[N],fa[N];//fa[x]:最终与x相关点
bool vis[N];//标记确定有色点
bool v[N];//标记已访问无色点
bool flagu;
void Init() {
	ans = cnt = 0;
	flagu=0;
	for(int i=1;i<=n;i++) fa[i]=i;
	for (int i = 0; i < N; i++) vector<Edge>().swap(g[i]);
	memset(vis, 0, sizeof(vis));
	memset(color, 0, sizeof(color));
	memset(v,0,sizeof(v));//debug:多测不清空...
}

void Search(int x) {
	if(color[x]==3) flagu=1;//连通块内有U,则全是U
	vis[x] = 1;
	cnt++;
	for (auto e : g[x])
		if (!vis[e.v]) Search(e.v);
}

void getsize(int x)
{
	v[x] = 1;
	cnt++;
	for (auto e : g[x])
		if (!v[e.v]) getsize(e.v);
}
bool dfs(int x, int c) { //是否不含U的二分图
	color[x] = c;
	//cnt++; debug:判二分图不能遍历到所有点
	//vis[x] = 1;
	//if(color[x]==3) return 0;//特判孤立点U
	for (auto e : g[x]) {
		int y = e.v, w = e.w;
		/*	if (color[y] == 3) { //连通块被U污染
		cnt--;
		return 0;
		}*/
		if(vis[y]) continue;
		if (!color[y]) { //未被染色
			if (w == 1&&!dfs(y,c)) return 0;//return dfs(y, c);debug:二分图一个节点里return 1不能代表全部都是return 1!!!!!
			else if(w==0&&!dfs(y, 3 - c)) return 0;
		} else if (color[y] == c && w == 0) {/*color[y]=3;*/return 0;}
		else if (color[y] == 3 - c && w == 1) {return 0;}
		//else if(color[y]==3) return 0; 	 	
	}
	return 1;
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> C >> t;
	while (t--) {
		cin >> n >> m;
		Init();
		while (m--) {
			char op;
			int x = 0, y = 0;
			cin >> op >> x;
			switch (op) {
				
				case 'T': {
					color[x] = 1;
					break;
				}
				case 'F': {
					color[x] = 2;
					break;
				}
				case 'U': {
					color[x] = 3;
					break;
				}
				case '+': {
					cin >> y;
					fa[x]=fa[y];
					color[x]=0;//debug:覆盖后就不是有色点!
					//add(y, x, 1);
					//add(x, y, 1); //debug:二分图判的是无向图!
					break;
				}
				default: {
					cin >> y;
					fa[x]=-fa[y];
					color[x]=0;
					//add(y, x, 0);
					//add(x, y, 0);
				}
			}
		}
		//for(int i=1;i<=n;i++){
		//	cout<<fa[i]<<' ';
		//}
		//if(t!=2) continue;
		for(int i=1;i<=n;i++)
		{
			if(!color[i])
			{
				//cout<<i<<' '<<fa[i]<<'\n';
				add(i,abs(fa[i]),fa[i]>0?1:0);
				add(abs(fa[i]),i,fa[i]>0?1:0);
			}	
		}	
	/*	for (int i = 1; i <= n; i++) {//有色点前驱染色
		if (!color[i])//如果没被染色
		for (auto e : g[i])
		if (color[e.v])
		color[i] = e.w ? color[e.v] : (3 - color[e.v]);
		}*/
		for (int i = 1; i <= n; i++) {//有色连通块排除
			cnt = 0;flagu=0;
			if (!vis[i] && color[i]) Search(i);
			if (flagu)	ans += cnt; //含U的连通块
			//cout<<cnt<<endl;
			//else if (color[i] == 3 && !g[i].size()) ans++;//特判孤立U点
		}
		for (int i = 1; i <= n; i++) {//无色连通块判二分图
			cnt = 0;
			if(!vis[i]&&!v[i])//无色 未被判过二分图
			{
				getsize(i);//计算连通块大小
				if (!dfs(i, 1)) /*cout<<cnt<<endl,*/ans += cnt;//非二分图,全是U
				
			}
		}
		cout << ans << '\n';
		//cout<<endl<<endl<<endl;
	}
	return 0;
}

2024/10/11 22:11
加载中...