2020 年 “遊族杯” 全國高校程序設計網絡挑戰賽 E.Even Degree(歐拉回路+歐拉路徑性質)

題目

n(1<=n<=5e5)個點,m(0<=m<=5e5)個點的無向圖,

保證所有點的度數爲偶數,無重邊,無自環

每次你可以選擇一條邊,只要這條邊當前連的兩個點的度數不同時爲奇數,就可刪掉這條邊

輸出最大的刪邊數k,及刪的k條邊的編號

思路來源

官方題解

題解

所有點的度數爲偶數,說明一定存在歐拉回路

考慮先隨便刪掉一條邊,剩下的轉化爲起點爲奇數,終點爲奇數,中間點爲偶數的歐拉路徑問題

最後一條邊一定刪不了,然後證剩下的都能刪,

 

如果歐拉路徑當前邊不均奇,則刪掉當前邊,

否則有當前點和下一個點(如代碼中被註釋掉的樣例)度同爲奇數,

則下一個點和下下個點不同時爲奇數(由於無重邊,是三個不同的點,否則不滿足歐拉路徑0/2奇度點要求)

則先刪下一條邊,再刪當前這條邊,然後沿歐拉路徑繼續走即可,

可取完除了最後一條邊的所有邊

 

注意圖不一定連通,所以對每個分量這麼刪

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
typedef pair<int,int> P;
const int N=5e5+10;
vector<P>e[N];
P f[N];
bool vis[N],used[N];
int now[N],ans[N],cnt,res[N],tot;
int n,m,u,v;
void dfs(int u){
	used[u]=1;
	while(now[u]<e[u].size()){
		int v=e[u][now[u]].first,id=e[u][now[u]].second;
		now[u]++;
		if(vis[id])continue;
		vis[id]=1;
		dfs(v);
		ans[++cnt]=id;
	}
}
int ano(int x,int id){
    return f[id].first^f[id].second^x;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		scanf("%d%d",&u,&v);
		f[i]=P(u,v);
		e[u].push_back(P(v,i));
		e[v].push_back(P(u,i));
	}
    for(int i=1;i<=n;++i){
        if(!e[i].size())continue;
        if(!used[i]){
            cnt=0;
            dfs(i);
            int now=i,nex=ano(i,ans[1]);
            res[++tot]=ans[1];
            for(int j=2;j<cnt;++j){
                if(ano(nex,ans[j])==now){
                    res[++tot]=ans[j+1];
                    res[++tot]=ans[j];
                    nex=ano(now,ans[j+1]);//連走兩條邊
                    j++;
                }
                else{
                    res[++tot]=ans[j];
                    nex=ano(nex,ans[j]);
                }
            }
        }
    }
    printf("%d\n",tot);
    for(int i=1;i<=tot;++i){
        printf("%d%c",res[i]," \n"[i==tot]);
    }
	return 0;
}
/*
5 7
1 3
1 4
1 5
1 2
2 3
2 4
2 5
*/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章