Kattis - pebblesolitaire

Kattis pebblesolitaire

題目

https://open.kattis.com/problems/pebblesolitaire

題目包含多筆測資,每筆測資有一個字串,字串當中只會有 -o 兩種字元

對於一個字串,如果有連續出現 -oo 或是 oo- ,我們可以選擇要不要把第一個以及最後一個交換,然後把中間換成 -

也就是 -oo -> o-- ; oo- -> --o

請問經過多次這樣的操作之後,字串中最少可以只剩下多少 o

想法

我們每次操作都必定只會讓 o 的數量減少,但是要在甚麼時機選擇進行操作是不明確的

這時候可以考慮枚舉,注意到每次 o 減少的數量都是固定的,那麼我們就可以用 BFS 來枚舉了

每次檢查字串中每個出現 -oo 以及 o-- 的位置,只要操作後的字串過去沒有出現過就可以繼續枚舉

那麼要怎麼檢查字串有沒有用過?

可以用位元運算來解決,我們用一個 int 的每個 bit 來記錄字串中某個位置是不是 o

例如 --o 就紀錄成 001,用十進位表示就是 2

字串長度固定會是 $12$,那麼我們只需要 $2^{12} = 4096$ 就可以紀錄全部的情況了

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//By Koios1143
#include<iostream>
using namespace std;
int n, stat;
string s, str, tmp, que[5000];
bool vis[5000];

int str_to_stat(string s){
// 把字串轉換成數字的狀態
int res = 0;
for(int i=0 ; i<s.size() ; i++){
if(s[i] == 'o'){
res |= (1<<i);
}
}
return res;
}

int BFS(){
que[0] = s;
vis[str_to_stat(s)] = true;

int i, j=1;
for(i=0, j=1 ; i<j ; i++){
str = que[i];
for(int k=0 ; k<str.size()-2 ; k++){
if((str[k] == 'o' && str[k+1] == 'o' && str[k+2] == '-') || (str[k] == '-' && str[k+1] == 'o' && str[k+2] == 'o')){
tmp = str;
swap(tmp[k], tmp[k+2]);
tmp[k+1] = '-';
stat = str_to_stat(tmp);
if(!vis[stat]){
vis[stat] = true;
que[j] = tmp;
j++;
}
}
}
}
return j-1;
}

int main(){
cin>>n;
while(n--){
for(int i=0 ; i<5000 ; i++){
vis[i] = false;
}
cin>>s;
int last = BFS();
int ans = 0;
for(int i=0 ; i<que[last].size() ; i++){
if(que[last][i] == 'o') ans++;
}
cout<<ans<<"\n";
}
return 0;
}

時間複雜度分析

每筆測資輸入時間複雜度為 $O(1)$

BFS 時間複雜度為 狀態數 $\times$ 操作數量,最多為 $4096 \times 10$

假設字串長度是 $s$,那麼 BFS 時間複雜度估計為 $O(10 \times 2^s)$

總時間複雜度為 $O(2^s \times n)$