• 【luogu P1989】无向图三元环计数(图论)(分类讨论)


    无向图三元环计数

    题目链接:luogu P1989

    题目大意

    给你一个无向图,问你有多少个三元组 (a,b,c),使得 ab,bc,ac 之间都有边。
    我们把不同排列得到的三元组看做一个。

    思路

    首先不难想到一些暴力的做法:
    直接枚举三个点 (O(n^3)),枚举两条边 (O(m^2)),枚举点和相邻的边 (O(nm))

    然而都过不了。
    我们考虑进行一个优化。
    考虑我们会重复计算一些,我们考虑把边弄成有向的(按照一定的方法)。
    我们考虑把点排优先级,从优先级大的连向优先级小的。

    然后我们可以把度数大的的优先级更大,如果入度相同就看点编号。
    那这样搞之后,我们考虑枚举一开始的点,然后标记处它能走到的点,然后按边扩展两步,如果扩展到的点一开始的点都能到,那就形成了一个三元环。
    然后这么搞就可以过。

    然后说一说如何判断走到的点和一开始的点是否有边。
    其实你就拿个数组记录一下那些点是能走到的,然后枚举枚举新的开始的点的时候更新一下就好了。

    那为什么呢?
    我们分情况讨论:(设新图入度为 (ru_i),出度为 (chu_i)

    1. 出度 (leqslant sqrt{m}),那所有点就是 (O(msqrt{m}))。((ru_i) 之和只有 (m)
    2. 初度 (>sqrt{m}),那由于边数是 (m),那这样的点不会超过 (sqrt{m}) 个,那复杂度总和还是 (O(msqrt{m}))

    所以复杂度就变成了 (O(msqrt{m}))

    代码

    #include<queue>
    #include<cstdio>
    #include<vector>
    
    using namespace std;
    
    int n, m, du[100001], x, y, ans;
    vector <int> lnk[100001], son[100001];
    queue <int> q;
    bool in[100001];
    
    int main() {
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i <= m; i++) {
    		scanf("%d %d", &x, &y);
    		lnk[x].push_back(y); lnk[y].push_back(x);
    	}
    	
    	for (int i = 1; i <= n; i++) {
    		for (int j = 0; j < lnk[i].size(); j++)
    			if (i < lnk[i][j]) {
    				if (lnk[i].size() >= lnk[lnk[i][j]].size()) {
    					son[i].push_back(lnk[i][j]); du[lnk[i][j]]++;
    				}
    				else son[lnk[i][j]].push_back(i), du[i]++;
    			}
    	}
    	
    	for (int i = 1; i <= n; i++) {
    		if (!du[i]) q.push(i);
    	}
    	while (!q.empty()) {
    		int now = q.front();
    		q.pop();
    		
    		for (int i = 0; i < son[now].size(); i++) {
    			du[son[now][i]]--;
    			if (!du[son[now][i]]) q.push(son[now][i]);
    			in[son[now][i]] = 1;//标记 x 可以到的点
    		}
    		for (int i = 0; i < son[now].size(); i++) {//枚举 x->y
    			for (int j = 0; j < son[son[now][i]].size(); j++)//枚举 y->x
    				if (in[son[son[now][i]][j]]) ans++;//看是否有 x->z
    		}
    		for (int i = 0; i < son[now].size(); i++) {
    			in[son[now][i]] = 0;
    		}
    	}
    	
    	printf("%d", ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    简单聊聊智能硬件的固件测试
    Regular进阶: 跨组件通信
    项目组建和磨合阶段常见的坑
    从需求到数据到改进,如何形成闭环
    请不要怪罪流程
    自备干货!如何有效的做竞品迭代分析
    css小点心
    java的collection集合
    java中的数组与集合相互转换
    java-增强for循环
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/luogu_P1989.html
Copyright © 2020-2023  润新知