zoukankan      html  css  js  c++  java
  • agc006_f Blackout

    agc006_f

    题目叙述

    给一个有向图,对于三个点如果 (u ightarrow v)(v ightarrow w)(u,v,w) 不一定两两不同),那么再连一条 (w ightarrow u) 的边。求最终的总边数。图可能有自环。

    题解

    对每个弱连通块分别考虑。弱连通块定义为将有向边视为无向边的连通块。

    将图用三种颜色红、黄、蓝染色。红色点只能向黄色点连边,黄色点只能向蓝色点连边,蓝色点只能向红色点连边。弱环定义为将所有边视为无向图形成的环。

    如果不存在一个这样的染色方法,设块的大小为 (x),那么将产生 (x^2) 条边。因为这样必然会有一个弱环满足他不能被染色。现在每次将这个弱环的边 (u ightarrow v)(v ightarrow w) 的边缩为 (w ightarrow u) ,那么这个弱环必将不断缩小,并且依旧不能用三种颜色染色。最终将会缩小成一个自环。一个自环将把整个环传染成一个完全图。

    如果一个图存在这样的染色方法,并且三种颜色都用上了,那么这个图必然还是只能红色点黄色点连边,黄色点只能向蓝色点连边,蓝色点只能向红色点连边。只要这个图存在一个三元环 (u ightarrow v,v ightarrow w,w ightarrow u) ,那么对于任意 (x)(u) 有边,那么必然会产生 (x ightarrow u,u ightarrow w,w ightarrow x) 。所以这样下去对于任意红色点会与任意黄色点右边,任意黄色点会向任意蓝色点有边,任意蓝色点会向绿色点有边。这样会产生 (rcdot y+ycdot b+bcdot r) 。其中 (r,y,b) 表示红色、黄色、蓝色点数量。

    如果存在染色方法并且至多两种颜色用上了,可以发现不能连出任何新边。

    这样做就行了。

    实现

    #include <cstdio>
    using namespace std;
    const int NN = 1e5 + 5, NM = 1e5 + 5;
    int N, M;
    struct E {
    	int v, nxt, fx;
    	E(int _v=0, int _nxt=0, int _fx=0) : v(_v), nxt(_nxt), fx(_fx) {}
    };
    struct Graph {
    	int head[NN], totE;
    	E edge[NM<<1];
    	void AddE(int u, int v, int fx) {
    		edge[++totE] = E(v, head[u], fx);
    		head[u] = totE;
    	}
    } G;
    int col[NN];
    bool vis[NN];
    int ys[] = {1, 2, 0};
    int fanys[] = {2, 0, 1};
    //0->1
    //1->2
    //2->0
    int cnt[3], egnum = 0, cc;
    bool Dfs(int u) {
    	vis[u] = 1;
    	cnt[col[u]] += 1;
    	int hoho = 0;
    	bool ret = 1;
    	for (int p = G.head[u]; p; p = G.edge[p].nxt) {
    		int v = G.edge[p].v;
    		++hoho;
    		if (vis[v]) {
    			if (G.edge[p].fx == 1 && col[v] != ys[col[u]]) {
    				ret = 0;
    			}
    			if (G.edge[p].fx == -1 && col[v] != fanys[col[u]]) {
    				//注意第一个 G.edge[p].fx == -1的条件
    				//以后限制能多写就多写 
    				ret = 0;
    			}
    			continue ;
    		}
    		if (G.edge[p].fx == 1)
    			col[v] = ys[col[u]];
    		else col[v] = fanys[col[u]];
    		if (!Dfs(v)) //记得这句话 
    			ret = 0;
    	}
    	egnum += hoho;
    	return ret;
    }
    int main() {
    	scanf("%d%d", &N, &M);
    	for (int i = 1; i <= M; ++i) {
    		int u, v;
    		scanf("%d%d", &u, &v);
    		G.AddE(u, v, 1);
    		G.AddE(v, u, -1);
    	}
    	long long ans = 0;
    	for (int i = 1; i <= N; ++i) {
    		if (!vis[i]) {
    			cnt[0] = cnt[1] = cnt[2] = 0;
    			egnum = 0; //初始化! 
    			bool jd = Dfs(i);
    			int sum = cnt[0] + cnt[1] + cnt[2];
    			//这里得 dfs完 cnt[0] cnt[1] cnt[2]才准确 
    			if (!jd) ans += (long long)sum * sum;
    			else if (!cnt[0] || !cnt[1] || !cnt[2]) ans += egnum / 2;
    			else ans += (long long)cnt[0] * cnt[1] +
    						(long long)cnt[1] * cnt[2] +
    						(long long)cnt[2] * cnt[0];
    		}
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    /*
    5 4
    1 2
    2 3
    4 5
    5 5
    */
    

    总结

    • 和三元环有关系的题考虑用三种颜色染色?
  • 相关阅读:
    Windows JScript 在 游览器 中运行 调试 Shell 文件系统
    autohotkey 符号链接 软连接 symbolink
    软链接 硬链接 测试
    SolidWorks 修改 基准面 标准坐标系
    手机 路径 WebDAV 映射 驱动器
    Win10上手机路径
    explorer 命令行
    单位公司 网络 封锁 屏蔽 深信 AC
    cobbler自动化部署原理篇
    Docker四种网络模式
  • 原文地址:https://www.cnblogs.com/YouthRhythms/p/13795035.html
Copyright © 2011-2022 走看看