大致題意:
給定一些木棒,木棒兩端都塗上顏色,求是否能將木棒首尾相接,連成一條直線,要求不同木棒相接的一邊必須是相同顏色的。
解題思路:
可以用圖論中尤拉路的知識來解這道題,首先可以把木棒兩端看成節點,把木棒看成邊,這樣相同的顏色就是同乙個節點
問題便轉化為:
給定乙個圖,是否存在「一筆畫」經過塗中每一點,以及經過每一邊一次。
這樣就是求圖中是否存在尤拉路euler-path。
回顧經典的「七橋問題」,相信很多同學馬上就明白了什麼是 尤拉路 了,這裡不多作解釋。
由圖論知識可以知道,無向圖存在尤拉路的充要條件為:
① 圖是連通的;
② 所有節點的度為偶數,或者有且只有兩個度為奇數的節點。
其中①圖的連通性用程式判斷比較麻煩,先放一下。
這裡先說說②關於度數的判斷方法:
blue
magenta
violet
cyan
red
節點的度用顏色出現次數來統計,如樣例中,藍色blue出現三次(不管是出度還是入度),那麼blue結點的度就為3,同樣地,我們也可以通過輸入得到其他全部結點的度,於是,我們有:
blue=3
red=2
violet=1
cyan=2
magenta=2
用乙個一維陣列就能記錄了,然後分別 模2,就能判斷顏色結點的奇偶性
只要奇度數的結點數的個數 = 1 或 >=3 ,即使①圖連通,尤拉路也必不存在
但是若 奇度數的結點數的個數 為0或 ==2,那麼我們繼續進行①圖的連通性證明:
證明①圖的連通性,使用並查集mergeset是非常高效的方法。
基本方法:
初始化所輸入的n個結點為n棵樹,那麼就有乙個n棵樹的森林,此時每棵樹的有唯一的結點(根),該結點的祖先就是它本身。再通過不斷地輸入邊,得到某兩個結點(集合)之間的關係,進而合併這兩個結點(集合),那麼這兩個集合就構成乙個新的集合,集合內的所有結點都有乙個共同的新祖先,就是這個集合(樹)的根。
最後只要列舉任意乙個結點,他們都具有相同的祖先,那麼就能證明圖時連通的了。
但是單純使用並查集是會超時的,因為這樣會導致每次尋找某個結點的祖先時,平均都會花費o(n/2)時間,最壞情況,當n==50w時,o(n/2)大概為25ms,那麼要確定50w個結點是否有共同祖先時,總費時為50w*25ms ,鐵定超,不算了= =
因此必須使用並查集時必須壓縮路徑,前幾次搜尋某個結點k的祖先時,在不斷通過父親結點尋找祖先結點時,順便把從k到最終祖先結點s中經過的所有結點的祖先都指向s,那麼以後的搜尋就能把時間降低到o(1)
由於並查集必須利用 陣列的下標 與 儲存的物件,使用int是比較方便的處理方法,但是題目的「顏色結點」是string,不方便用來使用並查集,即使用map也不行,雖然stl的map是基於hash的基礎上,但並不高效,在本題中使用會超時。
這個題目涉及了多個基本資料結構和演算法,綜合性很強,非常有代表性,能夠a到這題確實是受益良多。
#include
#include
#define maxs 500010
#include
#include
#define mme(i,j) memset(i,j,sizeof(i))
using
namespace
std;
int father[maxs],deg[maxs];
char head[15],tail[15];
int find_father(int x)
/*void joint(int x,int y)
*/typedef
struct node
trienode,*trie;//trie 樹
trie creat()
trie root;
void insert(char *s,trie root,int num)
p=p->nexts[id];
i++;
}p->num=num;
}int find(char *s,trie root)
p=p->nexts[id];
i++;
}return p->num;
}void init()
}void clear_trie(trie root)
bool ok(int cnt)
if(odd<=2)
return
1; return0;}
int main()
if(ok(cnt))
puts("possible");
else
puts("impossible");
clear_trie(root);
return
0;}
poj 2513(字典樹 尤拉通路)
題意 給你n個火柴棍,每個火柴棍頭和尾兩種顏色,問你是否存在能夠把這些火柴棍擺成一行的情況,兩個相連的火柴棍的顏色需要一樣 解題思路 最初的思路是用map標記顏色,然後把每種顏色看作點,每根火柴棍看作邊,求尤拉路徑,然後超時了。看了別人的寫法,想起來了自己還學過字典樹來著。然後用字典樹找就行了,快很...
一筆畫問題
一筆畫問題是在6x6的棋盤上分布著若干點,從紅色起點開始依次不重複地經過每個白色點,已經經過的點可以跨越過去。程式採用深度搜尋,從紅色點開始分別往上 往下 往左和往右邁出第一步,然後沿著當前方向,分別探測左邊 前面和右邊的下一結點,標記已經經過的節點為空。探測到左邊有節點就左轉,然後直行到該節點 如...
一筆畫問題
描述 判斷乙個圖是否能夠用一筆畫下來.規定,所有的邊都只能畫一次,不能重複畫。輸入第一行只有乙個正整數n n 10 表示測試資料的組數。每組測試資料的第一行有兩個正整數p,q p 1000,q 2000 分別表示這個畫中有多少個頂點和多少條連線。點的編號從1到p 隨後的q行,每行有兩個正整數a,b ...