1. 程式人生 > >HDU 6311 Cover 尤拉路徑,覆蓋

HDU 6311 Cover 尤拉路徑,覆蓋

題意:n點m條邊的無向圖,問最少用多少條路徑覆蓋整張圖,要求任意兩個路徑都不能有公共邊. 並輸出這些路徑.n,m<=1e5.

假如原圖為尤拉圖,那麼顯然只需要用一條迴路.
一條路徑中,最多隻會包含兩個奇數點,那麼答案>=odd/2 (odd為奇數點的個數.)

現在可以構造該答案.將奇數點兩兩連上虛擬邊.總共odd/2條邊.
在新的圖上跑一次歐拉回路,回溯時不標記這些虛擬邊,則迴路被拆成若干條路徑.
注意多個連通分量,以及孤立點的情況.

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,num,tot,head[N],deg[N];
bool vis[N];
vector<int> ans[N];
struct node{
	int v,id,nxt,flag;
}e[N*4];
void add(int u,int v,int id){
	e[tot].v=v,e[tot].id=id;
	e[tot].flag=0;
	e[tot].nxt=head[u],head[u]=tot++;
	
}
void dfs(int u){
	vis[u]=1;
	for(int i=head[u];i!=-1;i=e[i].nxt){
		int v=e[i].v;
		if(e[i].flag==false){
			e[i].flag=e[i^1].flag=true;
			dfs(v);
			if(e[i].id)	ans[num].push_back(-e[i].id);
			else num++;
		}
	}
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	while(cin>>n>>m){
		for(int i=0;i<=n;i++){
			deg[i]=vis[i]=0;
			head[i]=-1;
			ans[i].clear();
		}
		tot=num=0;
		for(int i=1;i<=m;i++){
			int u,v;
			cin>>u>>v;
			deg[u]++,deg[v]++;
			add(u,v,i);
			add(v,u,-i);
		}	
		int pre=0;
		for(int i=1;i<=n;i++){
			if(deg[i]&1){
				if(pre)	add(i,pre,0),add(pre,i,0),pre=0;
				else	pre=i;
			}
		}
		for(int i=1;i<=n;i++)
			if(!vis[i]&&(deg[i]&1))
				num++,dfs(i),num--;	
		for(int i=1;i<=n;i++)
			if(!vis[i]&&deg[i])//非孤立點 
				num++,dfs(i);
		cout<<num<<'\n';
		for(int i=1;i<=num;i++){
			cout<<ans[i].size();
			for(int j=0;j<ans[i].size();j++)
				cout<<' '<<ans[i][j];
			cout<<'\n';
		}
	}
	return 0;
}

求歐拉回路:dfs找到任意一個環 (dfs到一個點u:它沒有其他邊可以遍歷) 圖中剩下部分還是一條歐拉回路.從點u開始回溯,找剩下的環即可.