1. 程式人生 > 其它 >SSL_1438&&P2731【騎馬修柵欄】

SSL_1438&&P2731【騎馬修柵欄】

技術標籤:DFS圖論dfs圖論

騎馬修柵欄

題目

John 是一個與其他農民一樣懶的人。他討厭騎馬,因此從來不兩次經過一個柵欄。
John 的農場上一共有m個柵欄,每一個柵欄連線兩個頂點,頂點用1到500標號(雖然有的農場並沒有那麼多個頂點)。一個頂點上至少連線1個柵欄,沒有上限。兩頂點間可能有多個柵欄。所有柵欄都是連通的(也就是你可以從任意一個柵欄到達另外的所有柵欄)。John 能從任何一個頂點(即兩個柵欄的交點)開始騎馬,在任意一個頂點結束。
你需要求出輸出騎馬的路徑(用路上依次經過的頂點號碼錶示),使每個柵欄都恰好被經過一次。如果存在多組可行的解,按照如下方式進行輸出:如果把輸出的路徑看成是一個500進位制的數,那麼當存在多組解的情況下,輸出500進製表示法中最小的一個 (也就是輸出第一位較小的,如果還有多組解,輸出第二位較小的,以此類推)。

輸入資料保證至少有一個解。

Input

第一行一個整數m,表示柵欄的數目。
從第二行到第(m+1)行,每行兩個整數u,v,表示有一條柵欄連線u,v兩個點。

Output

共(m+1)行,每行一個整數,依次表示路徑經過的頂點號。注意資料可能有多組解,但是隻有上面題目要求的那一組解是認為正確的。
資料保證至少有一組可行解。

Sample Input

9
1 2
2 3
3 4
4 2
4 5
2 5
5 6
5 7
4 6

Sample Output

1
2
3
4
2
5
4
6
5
7

資料範圍

對於100%的資料,1<=m<=1024,1<=u,v<=500。


解析

這題很明顯是求一條字典序最短的迴路,一條迴路最多有兩個奇點,所以我們可以跑一趟DFS,注意要從奇點出發,但是還有一個問題:

假如沒有奇點呢?
如以下資料:
3
1 2
2 3
1 3
沒有奇點就代表可以從任何一點出發,所以可以先設為1(洛谷第一篇題解)
但是雖然AC了,就一定對了嗎?
不!
看從某大佬手中摘到的hack資料:
3
2 3
3 4
2 4
是不是差不多?
但是絕大部分題解輸出的是1
而題目中並沒有規定一定有1
那麼為什麼會AC呢?
大佬說:
資料中只有一個點是沒有奇點的,那個點資料有1頂點,所以能過
所以蒟蒻在此修改:
改為mn(mn是全部頂點中最小的一個)
19ms,吸氧後17ms(氧不行了?)
可以從某一本通上找來一筆畫的程式改一下(新增重邊)
進了第一頁就很不錯

code:

#include<cstdio>
#include<cstdlib> using namespace std; int m,a[510][510],mx,mn=500,q[250010],x,y,tot=0,s; int ma(int l,int r){return (l>r)?l:r;} int mi(int l,int r){return (l<r)?l:r;}//懶得加iostream bool t[510],ok;//記錄奇點 void dfs(int d)//跑DFS,越暴力,越快樂 { for(int i=mn;i<=mx;i++) { if(a[d][i]) { a[d][i]--,a[i][d]--; dfs(i); } } q[++tot]=d; return; } int main() { scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); mx=ma(ma(x,y),mx); mn=mi(mi(x,y),mn); a[x][y]++,a[y][x]++,t[x]=!t[x],t[y]=!t[y];//奇偶變換 } s=mn; for(int i=mn;i<=mx;i++)if(t[i])//第一個奇點 { s=i; break; } printf("%d",s); dfs(s); for(int i=m;i>=1;i--)printf("\n%d",q[i]); return 0; }