【NOIP2018 提高組 day2 T1】旅行
阿新 • • 發佈:2018-12-21
題目
思路
這道題60%的資料還是容易做; 這要建圖的時候預處理一下,如何深搜就行了; 因為兩點之間有且只有一條路徑聯通; 因此選擇了了一條邊,就必須把這棵子樹走完; 所以我們每次都選擇節點最小的那子樹; 貪心就完事;
考慮100%,發現n<=5000可以n2過,所以我們暴力刪掉環上的一條邊,在按60%跑一邊即可
程式碼比想象中長。。。
程式碼
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int n,m,u,v; struct node{ int next; int to; }e[10005]; int len,list[5005]; bool bol[5005]; int ans[5005],tot; int esave[5005],ecir[5005][5005]; bool cmp(const node &a,const node &b){ return a.next==b.next?a.to<b.to:a.next<b.next; } void esort(){ sort(e+1,e+1+len,cmp); for(int i=1;i<=len;i++){ if(list[e[i].next]==0)list[e[i].next]=i; } return; } void build(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d",&u,&v); len++; e[len].next=u; e[len].to=v; len++; e[len].next=v; e[len].to=u; } esort(); return; } void dfs(int p){ printf("%d ",p); bol[p]=1; for(int i=list[p];i<=len;i++){ if(e[i].next!=p)break; if(bol[e[i].to])continue; dfs(e[i].to); } return; } void solve(){ dfs(1); return; } int begin; bool findc(int p,int pre){ if(begin!=0)return 0; bol[p]=1; for(int i=list[p];i<=len;i++){ if(e[i].next!=p)break; if(e[i].to==pre)continue; if(bol[e[i].to]){ esave[++esave[0]]=i; begin=e[i].to; return 1; } if(findc(e[i].to,p)){ if(e[i].to==begin)return 0; else{ esave[++esave[0]]=i; return 1; } } } return 0; } bool co,sw; void spdfs(int p){ bol[p]=1; tot++; if(co)return; if(p>ans[tot]&&!sw){ co=1; return; } if(p<ans[tot]||sw){ ans[tot]=p; sw=1; } for(int i=list[p];i<=len;i++){ if(e[i].next!=p)break; if(bol[e[i].to]||ecir[p][e[i].to])continue; spdfs(e[i].to); } return; } void spsolve(){ findc(1,0);//???; memset(ans,0x7f,sizeof(ans)); for(int i=1;i<=esave[0];i++){ ecir[e[esave[i]].next][e[esave[i]].to]=ecir[e[esave[i]].to][e[esave[i]].next]=1; ecir[e[esave[i-1]].next][e[esave[i-1]].to]=ecir[e[esave[i-1]].to][e[esave[i-1]].next]=0; tot=0; co=0; sw=0; memset(bol,0,sizeof(bol)); spdfs(1); } for(int i=1;i<=n;i++)printf("%d ",ans[i]); return; } int main(){ build(); if(m==n)spsolve(); else solve(); return 0; }