• 【Luogu7816】「Stoi2032」以父之名


    「Stoi2032」以父之名

    题目大意

    给一个边权为 (1)(2) 的无向图,要求对每条边定向使得每个点的入度与出度之差的绝对值为 (1)。保证每个点的度数为奇数且存在一种方案。

    Solution

    考虑这个图只有 (1) 的边怎么做。因为每个点入度与出度之差为 (1),所以每个点的度数必为奇数,于是考虑建立一个虚点,向每个点连一条边,此时每个点度数为偶数(因为每个点的差均为 (1),而差值的和必为 (0),所以肯定是偶数个点),然后跑一次欧拉回路,欧拉回路所定方向即为一种可行解。

    那么,加入 (2) 的边的时候呢?

    我们分别考虑度数为奇数的点和度数为偶数的点。显然,对于入度为奇数的点,我们同样建立虚点向它们连边,又因为一条边会构造出两个度数为奇数的点,所以虚点的度数也为偶数,这个图仍是一个欧拉图。因为每个点的度数为奇数,所以原本度数为奇数的点必然有偶数条 (2) 和奇数条 (1),相对应的,原本度数为偶数的点必然有奇数条 (2) 和奇数条 (1)

    我们再考虑一个神奇的贪心算法:设之前转移过来的时候边权是 (w),则我们优先选择边权为 (w) 的边,否则再去选另一种边权的边。这样,度数为奇数的点全部奇数边和偶数边会分别进行匹配,去掉新加的边,入度与出度差即为 (1);度数为偶数的点,只有一组偶数和奇数边匹配,其它仍然是分别匹配。

    由此,我们在 (O(V+E)) 的时间内,解决了这道题。

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int num=0;char ch=getchar();
    	while(ch<'0'||ch>'9')ch=getchar();
    	while('0'<=ch&&ch<='9')num=num*10+ch-'0',ch=getchar();
    	return num;
    }
    const int MAXN=1e6+10;
    const int MAXM=8e6+10;
    struct qwq{
    	int v;
    	int w;
    	int nxt;
    }edge[MAXM];
    int cnt=-1;
    int head[MAXN];
    int h[MAXN][3];
    int nxt[MAXM];
    void adde(int u,int v,int w){
    	edge[++cnt].nxt=head[u];
    	edge[cnt].v=v;
    	edge[cnt].w=w;
    	nxt[cnt]=h[u][w];
    	h[u][w]=head[u]=cnt;
    }
    int n,m;
    int deg[MAXN];
    int ans[MAXM];
    void dfs(int u,int pre){
    	while(~h[u][pre]&&ans[h[u][pre]]!=-1)h[u][pre]=nxt[h[u][pre]];
    	if(!(~h[u][pre])){
    		pre=((pre-1)^1)+1;
    		while(~h[u][pre]&&ans[h[u][pre]]!=-1)h[u][pre]=nxt[h[u][pre]];
    	}
    	if(!(~h[u][pre]))return;
    	ans[h[u][pre]]=0,ans[h[u][pre]^1]=1;
    	int v=edge[h[u][pre]].v;
    	h[u][pre]=nxt[h[u][pre]];
    	dfs(v,pre);
    	for(int i=head[u];~i;i=edge[i].nxt){
    		head[u]=edge[i].nxt;
    		if(ans[i]!=-1)continue;
    		int v=edge[i].v;
    		ans[i]=0,ans[i^1]=1;
    		dfs(v,edge[i].w);
    	}
    }
    int main(){
    	memset(h,-1,sizeof(h));
    	memset(nxt,-1,sizeof(nxt));
    	memset(ans,-1,sizeof(ans));
    	memset(head,-1,sizeof(head));
    	n=read(),m=read();
    	for(int i=1;i<=m;++i){
    		int u=read(),v=read(),w=read();
    		adde(u,v,w),adde(v,u,w);
    		deg[u]++,deg[v]++;
    	}
    	for(int i=1;i<=n;++i){
    		if(deg[i]&1){
    			adde(n+1,i,1);
    			adde(i,n+1,1);
    		}
    	}
    	dfs(1,1);
    	for(int i=1;i<=m;++i){
    		putchar(ans[(i-1)<<1]?'1':'0');
    	}
    	putchar('
    ');
    }
    
  • 相关阅读:
    最大期望算法 Expectation Maximization概念
    Apriori 关联算法学习
    mysql小问题
    C4.5决策树算法概念学习
    线性回归概念学习
    决策树概念学习
    Flink on Yarn运行机制
    Flink单机版安装与wordCount
    Kmeans算法学习与SparkMlLib Kmeans算法尝试
    数据挖掘10大算法详细介绍
  • 原文地址:https://www.cnblogs.com/youddjxd/p/15177985.html
Copyright © 2020-2023  润新知