1. 程式人生 > >HDU 2894 DeBruijin (數位歐拉)

HDU 2894 DeBruijin (數位歐拉)

eof dfs bsp 解題思路 一個數 fin 如圖所示 這樣的 get

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=2894

題目大意:旋轉鼓的表面分成m塊扇形,如圖所示(m=8)。圖中陰影區表示用導電材料制成,空白區用絕緣材料制成,終端a、b和c是3(k=3)處接地或不是接地分別用二進制信號0或1表示。因此,鼓的位置可用二進制信號表示。試問應如何選取這8個扇形的材料使每轉過一個扇形都得到一個不同的二進制信號,即每轉一周,能得到000到111的8個數。

技術分享圖片


那我們現在把旋轉鼓的表面分成m塊扇形,每一份記為0或1,使得任何相繼的k個數的有序組(按同一方向)都不同,對固定的k,m最大可達到多少,並任意輸出符合條件的一個這樣的有序組。

Input 每個case輸入一個數k (2<=k<=11),表示圖中所示的abc這樣的接地線的數量。 Output 每個case輸出m所能達到的最大值 ,並且輸出字典序最小的一個符合條件的有序組,中間用空格隔開。Case間沒有空行。有序組輸出的格式為:00010111(k=3,只輸出一個周期(0001011100010111……),並且首尾剛好是相接的)。 解題思路:參考鏈接

第一問m達到的最大值為2^k。

第二問就是模擬一下旋轉鼓接地線的旋轉過程,每次旋轉即刪去第一個數,然後在最後加一個0(a<<1&((1<<k)-1))或1(a<<1&((1<<k)-1)+1),同時標記出現過的數字,保證每個出現的數字都不同。

因為所有數為0到2^k-1,對於任意給定的點a,將它與點a1=a<<1&((1<<k)-1)與點a2=a1+1分別連一條邊,構成歐拉回路(每個點入度=出度=2),加一個vis數組確定每個數出現一次。因為結果需要按照字典序從小到大排,所以首先輸出的必然是k個前導0,然後dfs判斷0或1時先判0,再判1,逆序輸出即可(dfs回溯)。

代碼:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define CLR(arr,val) memset(arr,val,sizeof(arr))
 5
using namespace std; 6 const int N=15; 7 8 int k,cnt; 9 int ans[1<<N]; 10 bool vis[1<<N]; 11 12 void init(){ 13 CLR(vis,false); 14 CLR(ans,0); 15 cnt=0; 16 } 17 18 void euler(int st) { 19 int s1=(st<<1)&((1<<k)-1); 20 int s2=s1+1; 21 if (!vis[s1]){ 22 vis[s1]=1; 23 euler(s1); 24 ans[++cnt]=0; 25 } 26 if (!vis[s2]) { 27 vis[s2]=1; 28 euler(s2); 29 ans[++cnt]=1; 30 } 31 } 32 33 int main(){ 34 while(~scanf("%d",&k)){ 35 init(); 36 euler(0); 37 printf("%d ",cnt); 38 //因為要求字典序最小,所以前k位都是0(前導零) 39 for(int i=1;i<k;i++){ 40 printf("0"); 41 } 42 for(int i=cnt;i>=k;i--){ 43 printf("%d",ans[i]); 44 } 45 printf("\n"); 46 } 47 return 0; 48 }

HDU 2894 DeBruijin (數位歐拉)