bzoj 3033: 太鼓達人 (尤拉圖+dfs)
3033: 太鼓達人
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 257 Solved: 198
[Submit][Status][Discuss]
Description
七夕祭上,Vani牽著cl的手,在明亮的燈光和歡樂的氣氛中愉快地穿行。這時,在前面忽然出現了一臺太鼓達人機臺,而在機臺前坐著的是剛剛被精英隊伍成員XLk、Poet_shy和lydrainbowcat拯救出來的的applepi。看到兩人對太鼓達人產生了興趣,applepi果斷閃人,於是cl拿起鼓棒準備挑戰。然而即使是在普通難度下,cl的路人本性也充分地暴露了出來。一曲終了,不但沒有過關,就連鼓都不靈了。Vani十分過意不去,決定幫助工作人員修鼓。
鼓的主要元件是M個圍成一圈的感測器。每個感測器都有開和關兩種工作狀態,分別用1和0表示。顯然,從不同的位置出發沿順時針方向連續檢查K個感測器可以得到M個長度為K的01串。Vani知道這M個01串應該是互不相同的。而且鼓的設計很精密,M會取到可能的最大值。現在Vani已經瞭解到了K的值,他希望你求出M的值,並給出字典序最小的感測器排布方案。
Input
一個整數K。
Output
一個整數M和一個二進位制串,由一個空格分隔。表示可能的最大的M,以及字典序最小的排布方案,字元0表示關,1表示開。你輸出的串的第一個字和最後一個字是相鄰的。
Sample Input
3Sample Output
HINT
得到的8個01串分別是000、001、010、101、011、111、110和100。注意前後是相鄰的。長度為3的二進位制串總共只有8種,所以M = 8一定是可能的最大值。
對於全部測試點,2≤K≤11。
Source
題解:尤拉圖+dfs
之前就知道尤拉圖,但是一直沒有仔細的學過,也基本上沒有應用過。
先引出尤拉圖的一些基本概念
1.尤拉通路:通過圖中的每條邊一次且僅一次,並且過每個頂點的通路
2.歐拉回路:通過圖中的每條邊一次且僅一次,並且過每個頂點的迴路
3.尤拉圖:存在歐拉回路的圖。尤拉圖就是從一個頂點出發每條邊恰經過一次又回到出發頂點的那種圖,即不重複的行遍所有的邊再回到出發點。
4.簡單圖:不含平行邊和自由路的圖
5.混合圖:既有有向邊,也有無向邊的圖
6.平凡圖:僅一個節點的圖
7.完全圖:有n個結點且每對結點都有邊相連的無向簡單圖,稱為無向完全圖。有n個結點的且每對結點之間都有兩條方向相反的邊相連的有向簡單圖,稱為有向完全圖。
無向圖
(1)G有尤拉通路的充分必要條件為:G聯通,G中只有兩個奇數頂點(分別是尤拉通路的兩個端點)
(2)G有歐拉回路(G為尤拉圖):G聯通,G中均為偶度頂點
有向圖
(1)D有尤拉通路:D聯通,除兩個頂點外,其餘頂點的入度出度相等,這兩個特殊的頂點中,一個頂點的入度比出度大1,另一個頂點的入度比出度小1
(2)D有歐拉回路(D為尤拉圖):D聯通,D中所有頂點的入度等於出度。一個有向圖是尤拉圖,當且僅當該圖所有頂點的度數都是0
對於這道題來說,01串的所有組合有2^k種,但是直接分析的話並不能確定所有的組合一定都能出現。
但是我們將所有的組合都看成一個點,那麼每個點在最後加上0或1,使01串的長度為k,有兩種選擇,同樣再前面新增0或1也是一樣。那麼對於每個點來說出度和入度是相同的,也就是說我們可以得到一種有向的尤拉圖。
對於尤拉圖來說,一定存在歐拉回路,也就是說一定存在方案使2^k中組合都出現。
同時因為是尤拉圖,那麼這道題基本上就變成了一筆畫問題,對於一筆畫問題的話我們可以放心的dfs,會在非常高的效率內出解。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 3000
using namespace std;
int vis[N],ans[N];
int n,t;
int dfs(int x,int k)
{
if (vis[x]) return 0;
if (k==t) return 1;
vis[x]=1; ans[k]=x&1;
if (dfs((x<<1)&(t-1),k+1)) return 1;
if (dfs((x<<1|1)&(t-1),k+1)) return 1;
vis[x]=0;
return 0;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&n);
printf("%d ",(t=1<<n));
dfs(0,1);
for (int i=1;i<n;i++) printf("0");
for (int i=1;i<=t-n+1;i++)
printf("%d",ans[i]);
printf("\n");
}