時間限制1s,內存限制256MB。
題目描述
據說大主任認識一個自認爲很聰明的人。
有一天,大主任問那個人:
“你能告訴我一個集合的表示法嗎?”
“當然,我這麼聰明!”他回答說,“那是一組在兩個大括號包圍的元素,但括號裏也可以爲空,這些元素可以是一個新的集合,也可以是一個字母,他們之間用','隔開。”
“那麼,”大主任說,“如果我給你一個表示,你能告訴我它是一個正確的集合嗎?”
“當然,我這麼聰明!”他又回答說,“傻瓜都會做!”
“很好,”大主任想,“這樣我就可以證明他是傻瓜了!”
現在大主任準備用這樣一道題來虐掉那個人。你將得到下列規定:
集合:{元素列表}
元素列表:空 or 元素子列表
元素子列表:元素 or 元素 , 元素子列表
元素:子元素 or 集合
子元素:{ or , or }
注意:“空”,表示沒有任何成分,並不是有一個表示“空”的字符。
大主任覺得這題太水了,他不屑於寫標程,倒是給出了一大堆邪惡的數據。爲了幫助大主任證明那個人是傻瓜,作爲大主任下手的你也就難逃幫他寫標程的厄運了。
請你寫一個程序判斷一個表達式是否滿足上述規定的集合。
輸入描述
本題有多組數據。
輸入的第一行爲數據組數T。
第2行到第T+1行,每行給出一個字符串。
輸出描述
共T行。
按下列格式輸出:
若是一個滿足規定的集合,則輸出:Word #數據組編號: Set
若不是,則輸出: Word #數據組編號: No Set
輸入樣例
4
{}
{{}}
{{}},{,}}
{,,}
輸出樣例
Word #1: Set
Word #2: Set
Word #3: Set
Word #4: No Set
提示
如果你覺得題面太糾結了,那麼請看第三個樣例,它爲什麼是合法的。
{ {}} , {,} }
數據範圍及約定
對於20%的數據,|S|<=10。
對於100%的數據,T<=10,|S|<=100。
寫完拍完那個噁心的mm數據結構根本沒有時間了。。。
什麼速度...算了不說了。
這個題。。“題面太糾結”是極佳的概述啊!
當然我也是語死早,
其實他是一個區間DP啊!
最暴力可以記錄f[5][L][R],分別表示一段區間能否構成題面上告訴的哪些什麼怪物東西。
再想一下發現可以只用記錄能不能集合和集合列表。
當然其實只用F[L][R],因爲集合和集合列表也是沒有區別的啊。
最後只用判斷C[1]和C[n]是不是‘{’ ‘}’,在判斷F[2][n-1]能否構成一個集合或集合列表。
然後。。就木有然後了。
O(n^3)
區間DP先枚舉區間長度當然無可厚非(就像本沙茶的代碼)。
不過diamondlx吊方法:
從右向左枚舉L,再從左向右枚舉R,這樣就能構成一個拓撲序列。~~~
其實我以前也發現這種順序太渣。。但是也沒有什麼更好的方法,
今天領教了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
const int MAX_N=105;
bool f[MAX_N][MAX_N];
char c[MAX_N];
bool check(){
int n=strlen(c+1);
if (n==2){
if(c[1]=='{'&&c[2]=='}') return true;
else return false;
}
rep(i,1,n) f[i][i]=1;
rep(i,1,n-1)
if (c[i]=='{'&&c[i+1]=='}') f[i][i+1]=1;
rep(i,3,n)
rep(l,1,n-i+1){
int r=l+i-1;
if (c[l]=='{'&&c[r]=='}') f[l][r]|=f[l+1][r-1];
rep(k,l+1,r-1){
if (c[k]==',') f[l][r]|=f[l][k-1]&f[k+1][r];
}
}
//rep(l,1,n) rep(r,l,n)
// printf("%d %d %d\n",l,r,f[l][r]);
if (c[1]=='{'&&c[n]=='}') return f[2][n-1];
return false;
}
int main(){
freopen("set.in","r",stdin);
freopen("set.out","w",stdout);
int T;scanf("%d",&T);
rep(i,1,T){
scanf("%s",c+1);
memset(f,0,sizeof f);
if (check()) printf("Word #%d: Set\n",i);
else printf("Word #%d: No Set\n",i);
}
}