題目
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
*/