HDU 3018 Ant Trip (尤拉路)
阿新 • • 發佈:2018-11-09
題目大意:一個隊想遍訪所有小城,每個隊每條路只能走一次,該隊可被分成了很多小隊,求得使能夠遍訪所有小城的最小隊數。
演算法:尤拉路+並查集
難度:NOIP
題解:
首先,用並查集處理出每個連通塊,並且讀入時統計每個點的度數,然後在每個連通塊內進行列舉,如果一個連通塊內都是偶數度的點,那麼這個連通塊就可以由一個小隊走完,如果這個連通塊內有奇數度的點,那麼就說明一個小隊是走不完的,該集合構成了非歐拉回路的其他連通集。則需要奇度總數/2個小隊數。因為一條尤拉路徑最多有兩個奇度點
注意:孤立的一個點不用去考慮!
程式碼如下(my code) 有點亂:
#include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <queue> #define ll long long #define N 100005 using namespace std; int fa[N]; int findf(int x) { if(x==fa[x]) return x; return fa[x]=findf(fa[x]); } int deg[N]; int vis[N]; struct node { int idd; int tag; }aa[N]; int cmp(node x,node y) { return x.tag< y.tag; } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { memset(deg,0,sizeof(deg)); memset(vis,0,sizeof(vis)); memset(aa,0,sizeof(aa));//這個陣列一定要記得清!!! for(int i = 1;i <= n;i++) { fa[i]=i; } for(int i = 1;i <= m;i++) { int a,b; scanf("%d%d",&a,&b); deg[a]++,deg[b]++; int t1=findf(a); int t2=findf(b); if(t1!=t2) fa[t1]=t2; vis[a]=1,vis[b]=1; } for(int i = 1;i <= n;i++) { if(!vis[i]) continue; int f=findf(i); aa[i].tag=f; aa[i].idd=i; } sort(aa+1,aa+1+n,cmp); int ans=0; int aas=0,ctt=0; for(int i = 1;i < n;i++) { if(aa[i].tag==0) continue; if(aa[i].tag==aa[i+1].tag) { aas+=deg[aa[i].idd]+deg[aa[i+1].idd]; if(deg[aa[i].idd]%2) ctt++; if((deg[aa[i+1].idd]%2)&&(i==n-1)) ctt++; }else { if(ctt) { ans+=(ctt+1)/2; }else { ans+=1; } ctt=0; aas=0; } if(i==n-1) { if(ctt) { ans+=(ctt+1)/2; }else { ans+=1; } ctt=0; aas=0; } } printf("%d\n",ans); } return 0 ; }
大佬程式碼如下:
#include<iostream> #include<cstring> using namespace std; const int maxn=1e5+5; int par[maxn],in[maxn],cnt[maxn],odd[maxn]; int N,M; int a,b; int ans; void init() { for(int i=1;i<=N;i++) par[i]=i; memset(in,0,sizeof(in)); memset(cnt,0,sizeof(cnt)); memset(odd,0,sizeof(odd)); ans=0; } int find(int a) { if(a==par[a])return a; return par[a]=find(par[a]); } void unite(int a,int b) { a=find(a); b=find(b); if(a==b)return ; else if(a>b) par[a]=b; else par[b]=a; } int main() { ios::sync_with_stdio(false); while(cin>>N>>M) { init(); for(int i=0;i<M;i++) { cin>>a>>b; unite(a,b); in[a]++;in[b]++;//統計節點度 } for(int i=1;i<=N;i++) { cnt[find(i)]++;//統計i的根節點的節點數 if(in[i]%2)odd[find(i)]++;//統計i的根節點的節點奇度數 } for(int i=1;i<=N;i++) { if(cnt[i]<=1)continue;//獨立的點不用考慮或者不為根節點的點不考慮 else if(odd[i]==0)ans++;//構成歐拉回路一筆畫 else if(odd[i]>0)ans+=odd[i]/2;//沒有構成歐拉回路奇度/2 } cout<<ans<<endl; } return 0; }