• 【PNR#2 Div1 C】图同构(图论)


    图同构

    题目链接:PNR#2 Div1 C

    题目大意

    给你两个边集一样的图,点有黑白两色,而且有点权。
    你操作若干次,每次选择一条边,把连着的两个点点权交换,若两点同色则同时反色。
    然后问你 A 图能否通过操作得到 B 图。

    思路

    发现部分分有个二分图,思考一下。

    发现这个颜色的操作很迷,考虑放到二分图上。
    发现如果你把其中的一边的点都反色一下,那操作就变成了交换两边的颜色。
    那就跟交换边权统一了。

    那我们就可以对于每个连通块,查询它们有的点权+颜色集合是否一样即可。

    接着问题是不是二分图,考虑会有什么影响。
    而且首先一定会有的是奇环。
    然后考虑操作这条边会怎样。
    那你可以内部选一样的颜色消去,那也就是说,你两个图,需要的颜色的差是偶数倍的话,你就可以把它转成不相差。
    然后也就没啥了,那如果可以的话你就不用判断颜色了。

    代码

    #include
    #include
    #include
    
    using namespace std;
    
    const int N = 1e6 + 100;
    struct node {
    	int to, nxt;
    }e[N << 1];
    int T, n, m, le[N], KK, col[N], tot;
    int a[N], b[N], G1, G2;
    vector <int> A[2], B[2];
    char s[N], t[N];
    bool Op[N], ji;
    
    void clr() {
    	for (int i = 1; i <= n; i++) le[i] = 0; KK = 0;
    	for (int i = 1; i <= n; i++) col[i] = 0; tot = 0;
    }
    
    void add(int x, int y) {
    	e[++KK] = (node){y, le[x]}; le[x] = KK;
    }
    
    void dfs(int now, int op) {
    	if (col[now]) {
    		if (Op[now] != op) ji = 1;
    		return ;
    	}
    	col[now] = tot; Op[now] = op;
    	A[(s[now] == 'R') ^ op].push_back(a[now]);
    	B[(t[now] == 'R') ^ op].push_back(b[now]);
    	if (s[now] == 'R') G1++; if (t[now] == 'R') G2++;
    	for (int i = le[now]; i; i = e[i].nxt)
    		dfs(e[i].to, op ^ 1);
    }
    
    bool same(vector <int> a, vector <int> b) {
    	sort(a.begin(), a.end()); sort(b.begin(), b.end());
    	return a == b;
    }
    
    int main() {
    	scanf("%d", &T);
    	while (T--) {
    		scanf("%d %d", &n, &m);
    		for (int i = 1; i <= m; i++) {
    			int x, y; scanf("%d %d", &x, &y);
    			add(x, y); add(y, x);
    		}
    		for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    		scanf("%s", s + 1);
    		for (int i = 1; i <= n; i++) scanf("%d", &b[i]);
    		scanf("%s", t + 1);
    		
    		bool yes = 1;
    		for (int i = 1; i <= n; i++)
    			if (!col[i]) {
    				A[0].clear(); A[1].clear(); B[0].clear(); B[1].clear();
    				G1 = G2 = 0; ji = 0;
    				tot++; dfs(i, 0);
    				if (ji) {
    					for (int j = 0; j < A[1].size(); j++) A[0].push_back(A[1][j]);
    					for (int j = 0; j < B[1].size(); j++) B[0].push_back(B[1][j]);
    					if ((G1 - G2) % 2 != 0 || !same(A[0], B[0])) {
    						yes = 0; break;
    					}
    				}
    				else {
    					if ((G1 - G2) % 2 != 0 || !same(A[0], B[0]) || !same(A[1], B[1])) {
    						yes = 0; break;
    					}
    				}
    			}
    		
    		clr();
    		if (yes) printf("YES\n");
    			else printf("NO\n");
    	}
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
  • 相关阅读:
    使用任务表,实现两个数据库表数据迁移
    容器内存指标
    C语言学习-数组应用-三子棋(4.1)
    qpoases解MPC控制
    会议信息管理系统SSM记录(六)
    Android中 BufferQueue 和 Gralloc
    Java观察者模式之总有你想不到的知识
    基于python的家政管理系统毕业设计源码071111
    辩证性在需求面前毫无逻辑
    互联网Java工程师面试题·Spring篇·第五弹
  • 原文地址:https://blog.csdn.net/weixin_43346722/article/details/127558977