ACM.ZJU 2800 判断给定输入是否是一个集合

孩皮妞野 2007-10-28 02:28:22
形式语法
Set ::= "{" Elementlist "}"
Elementlist ::= <empty> | List
List ::= Element | Element "," List
Element ::= Atom | Set
Atom ::= "{" | "}" | ","

要求写一个程序,高效的判断给定输入是否是集合。每行最大长度为200个字符。

示例输入
3
{{{}}
{{},{,,{{}},{},{}}},{{,}},},}}
{{,},{},{,},}}

示例输出
Word #1: Set
Word #2: Set
Word #3: Set
Word #4: No Set

我试了回溯法等,超时,后来想到可以用动态规划法。程序好写,但是结果错误。想破脑袋不知道那里边界没有考虑到,
下面是我的程序,请师傅们帮忙找找漏洞。
...全文
342 20 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
孩皮妞野 2007-10-31
  • 打赏
  • 举报
回复
呵呵,逻辑很简单的。C兄说的是对的,我怕侵权,准备自己整例子,后来一乱例子和输出结果没配上。

形式语法是没有问题的,这个我是原封复制过来的。逻辑也不复杂吧,编译原理没忘光的话,看懂语法应该没问题吧。

我为了实现的方便,对语法作了一定的恒等变形,如此而已。
C1053710211 2007-10-30
  • 打赏
  • 举报
回复
原sample input是
4
{}
{{}}
{{}},{,}}
{,,}
output 是
Word #1: Set
Word #2: Set
Word #3: Set
Word #4: No Set

可能是lz贴错了,而且lz的算法是正确的
bigc2000 2007-10-30
  • 打赏
  • 举报
回复
我记得在数据结构里有一个专门的讲到了 广义表,应该就是这种,估计这种最快。
另外,从文法上看,递归下降分析,LL(1)可以,但可能会超时,
我以前做这类正则文法,是用DFA,让后最小化,来求得,

代码早就丢了(本科的时候常写这类的)
Tiger_Zhao 2007-10-30
  • 打赏
  • 举报
回复
同意12楼,输入 3 明显不符合定义 "{" Elementlist "}" 。
kaishui_gu 2007-10-30
  • 打赏
  • 举报
回复
这种东西的逻辑比较复杂,没看懂LS说的;
C1053710211 2007-10-30
  • 打赏
  • 举报
回复
{,,} 是错误的,因为根据这个文法,第一个","只能是一种情况,即","是Element中的候选式Atom,
但是一个List中不能出现两个Element连续出现的情况,Element之间需要一个","将它们分开(就是第二个","),
而","的两侧需要List,Set或Atom,第二个","后面什么都没有,但是List中没有"空"这个候选式,
所以它不符合这个文法。是no set。
kaishui_gu 2007-10-30
  • 打赏
  • 举报
回复
不是例子,而是形式语法定义有问题
就算是
4
{}
{{}}
{{}},{,}}
{,,}
那么按照LZ的定义应该都是正确的
Tiger_Zhao 2007-10-30
  • 打赏
  • 举报
回复
原来第一个是需要测试的集合数,问题都没描述清楚!
C1053710211 2007-10-29
  • 打赏
  • 举报
回复
晕,输出格式错误还judge我0.12秒,他知道格式错误应该0.00秒WA呀,这不是阴人吗,吐血而死!!!
lz的代码注释加的很艺术,是我见过最清晰的,顶
mathe 2007-10-29
  • 打赏
  • 举报
回复
to ALING
看来你也很多年前就上CSDN了:)
mathe 2007-10-29
  • 打赏
  • 举报
回复
修改后的代码
例子:
$ ./isset "{{},{,,{{}},{},{}}},{{,}},},}}"
Set
{{},{,,{{}},{},{}}},{{,}},},}}
{{},{E,{E}},{E,{E}},{E,E},E,E}

#include <stdio.h>
#include <set>
using namespace std;
#define MAX_LEN 1000
class STATE{
private:
short numberLeft;
char s;
char the_char;
public:
STATE(short left, char state, char input):numberLeft(left),s(state),the_char(input){}
bool operator<(const STATE& s)const{
if(numberLeft<s.numberLeft)return true;
else if(numberLeft>s.numberLeft)return false;
if(this->s<s.s)return true;
else return false;
return false;
}
bool operator==(const STATE& s)const{
return numberLeft==s.numberLeft&&this->s==s.s;
}
char getState()const{return s;}
int getLeft()const{return numberLeft;}
void increaseLeft(){numberLeft++;}
char getInputChar()const{return the_char;}
STATE findPrevState(char c,int prev,bool last_pass)const;
};


typedef set<STATE> STATE_SET;

STATE_SET sets[MAX_LEN];

STATE STATE::findPrevState(char c,int prev,bool last_pass)const
{
STATE_SET::iterator it;
for(it=sets[prev].begin();it!=sets[prev].end();++it){
const STATE& s=*it;
switch(s.getState()){
case '{':
if(c=='{'){
STATE ns1(s.getLeft()+1,'{','{');
if(ns1==*this)return s;
STATE ns2(s.getLeft(),'E','E');
if(ns2==*this)return s;
}else if(c=='}'){
STATE ns1(s.getLeft(),'E','E');
if(ns1==*this)return s;
if(s.getLeft()>1||s.getLeft()==1&&last_pass){
STATE ns2(s.getLeft()-1,'E','}');
if(ns2==*this)return s;
}
}else{//c==','
STATE ns(s.getLeft(),'E','E');
if(ns==*this)return s;
}
break;
case ',':
if(c=='{'){
STATE ns1(s.getLeft()+1,'{','{');
if(ns1==*this)return s;
STATE ns2(s.getLeft(),'E','E');
if(ns2==*this)return s;
}else if(c=='}'){
STATE ns1(s.getLeft(),'E','E');
if(ns1==*this)return s;
}else{//c==','
STATE ns(s.getLeft(),'E','E');
if(ns==*this)return s;
}
break;
case 'E':
if(c=='{'){
}else if(c=='}'){
if(s.getLeft()>1||s.getLeft()==1&&last_pass){
STATE ns(s.getLeft()-1,'E','}');
if(ns==*this)return s;
}
}else{//c==','
STATE ns(s.getLeft(),',',',');
if(ns==*this)return s;
}
break;
}
}
}

void build_sets_i(int step, char c,bool last_pass)
{
STATE_SET::iterator it;
for(it=sets[step-1].begin();it!=sets[step-1].end();++it){
const STATE& s=*it;
switch(s.getState()){
case '{':
if(c=='{'){
sets[step].insert(STATE(s.getLeft()+1,'{','{'));
sets[step].insert(STATE(s.getLeft(),'E','E'));
}else if(c=='}'){
sets[step].insert(STATE(s.getLeft(),'E','E'));
if(s.getLeft()>1||s.getLeft()==1&&last_pass){
sets[step].insert(STATE(s.getLeft()-1,'E','}'));
}
}else{//c==','
sets[step].insert(STATE(s.getLeft(),'E','E'));
}
break;
case ',':
if(c=='{'){
sets[step].insert(STATE(s.getLeft()+1,'{','{'));
sets[step].insert(STATE(s.getLeft(),'E','E'));
}else if(c=='}'){
sets[step].insert(STATE(s.getLeft(),'E','E'));
}else{//c==','
sets[step].insert(STATE(s.getLeft(),'E','E'));
}
break;
case 'E':
if(c=='{'){
}else if(c=='}'){
if(s.getLeft()>1||s.getLeft()==1&&last_pass){
sets[step].insert(STATE(s.getLeft()-1,'E','}'));
}
}else{//c==','
sets[step].insert(STATE(s.getLeft(),',',','));
}
break;
}
}
}

int main(int argc, char *argv[]){
int i,len;
char *input;
char *trace;
if(argc!=2){
fprintf(stderr,"Usage: %s \"string of {},\"\n",argv[0]);
return -1;
}
input=argv[1];
for(i=0;input[i]!='\0';i++){
if(input[i]!='{'&&input[i]!='}'&&input[i]!=','){
fprintf(stderr,"Invalid input\n");
return -1;
}
}
if(i>MAX_LEN){
fprintf(stderr,"Too Long input\n");
return -1;
}
if(input[0]!='{'||input[i-1]!='}'){
printf("No Set\n");
return 0;
}
len = i;
sets[0].insert(STATE(1,'{','{'));
for(i=1;i<len;i++){
build_sets_i(i,input[i],i==len-1);
}
#if 0
for(i=0;i<len;i++){
fprintf(stderr,"TRACE %d:\n",i);
STATE_SET::iterator it;
for(it=sets[i].begin();it!=sets[i].end();++it){
fprintf(stderr,"\t%d,%c,%c\n",it->getLeft(),it->getState(),it->getInputChar());
}
}
#endif
STATE_SET::iterator it;
for(it=sets[len-1].begin();it!=sets[len-1].end();++it){
if(it->getLeft()==0){///find a solution for set
break;
}
}
if(it==sets[len-1].end()){
printf("No Set\n");
}else{
printf("Set\n");
///Next show how to treat the set;
printf("%s\n",input);
trace = new char[len+1];
trace[len]='\0';
STATE s=*it;
for(i=len-1;i>0;i--){
trace[i]=s.getInputChar();
s = s.findPrevState(input[i],i-1,i==len-1);
}
trace[0]=s.getInputChar();
printf("%s\n",trace);
delete []trace;
}
}
mathe 2007-10-29
  • 打赏
  • 举报
回复
写了一段代码,可以判断是否结果是集合,如果是集合,把它的集合形式输出:
比如:
$ ./isset "{{},{,,{{}},{},{}}},{{,}},},}}"
Set
{{},{,,{{}},{},{}}},{{,}},},}}
{{E,E,,{E}},{E,{E}},{E,E},E,E}
上面的输出中,第一行Set表示结果是集合
第二行重新输出输入数据
第三行输出每个数据被如何处理,E表示将这个数据当成元素,不然当成它本身的意义.
不过现在发现我有一个理解错误了,原先我一位两个','之间可以是空,现在重新看了下题目,发现不行,等会修改再发

#include <stdio.h>
#include <set>
using namespace std;
#define MAX_LEN 1000
class STATE{
private:
short numberLeft;
char s;
char the_char;
public:
STATE(short left, char state, char input):numberLeft(left),s(state),the_char(input){}
bool operator<(const STATE& s)const{
if(numberLeft<s.numberLeft)return true;
else if(numberLeft>s.numberLeft)return false;
if(this->s<s.s)return true;
else return false;
return false;
}
bool operator==(const STATE& s)const{
return numberLeft==s.numberLeft&&this->s==s.s;
}
char getState()const{return s;}
int getLeft()const{return numberLeft;}
void increaseLeft(){numberLeft++;}
char getInputChar()const{return the_char;}
STATE findPrevState(char c,int prev,bool last_pass)const;
};


typedef set<STATE> STATE_SET;

STATE_SET sets[MAX_LEN];

STATE STATE::findPrevState(char c,int prev,bool last_pass)const
{
STATE_SET::iterator it;
for(it=sets[prev].begin();it!=sets[prev].end();++it){
const STATE& s=*it;
switch(s.getState()){
case '{':
case ',':
if(c=='{'){
STATE ns1(s.getLeft()+1,'{','{');
if(ns1==*this)return s;
STATE ns2(s.getLeft(),'E','E');
if(ns2==*this)return s;
}else if(c=='}'){
STATE ns1(s.getLeft(),'E','E');
if(ns1==*this)return s;
if(s.getLeft()>1||s.getLeft()==1&&last_pass){
STATE ns2(s.getLeft()-1,'E','}');
if(ns2==*this)return s;
}
}else{//c==','
STATE ns(s.getLeft(),',',',');
if(ns==*this)return s;
}
break;
case 'E':
if(c=='{'){
}else if(c=='}'){
if(s.getLeft()>1||s.getLeft()==1&&last_pass){
STATE ns(s.getLeft()-1,'E','}');
if(ns==*this)return s;
}
}else{//c==','
STATE ns(s.getLeft(),',',',');
if(ns==*this)return s;
}
break;
}
}
}

void build_sets_i(int step, char c,bool last_pass)
{
STATE_SET::iterator it;
for(it=sets[step-1].begin();it!=sets[step-1].end();++it){
const STATE& s=*it;
switch(s.getState()){
case '{':
case ',':
if(c=='{'){
sets[step].insert(STATE(s.getLeft()+1,'{','{'));
sets[step].insert(STATE(s.getLeft(),'E','E'));
}else if(c=='}'){
sets[step].insert(STATE(s.getLeft(),'E','E'));
if(s.getLeft()>1||s.getLeft()==1&&last_pass){
sets[step].insert(STATE(s.getLeft()-1,'E','}'));
}
}else{//c==','
sets[step].insert(STATE(s.getLeft(),',',','));
}
break;
case 'E':
if(c=='{'){
}else if(c=='}'){
if(s.getLeft()>1||s.getLeft()==1&&last_pass){
sets[step].insert(STATE(s.getLeft()-1,'E','}'));
}
}else{//c==','
sets[step].insert(STATE(s.getLeft(),',',','));
}
break;
}
}
}

int main(int argc, char *argv[]){
int i,len;
char *input;
char *trace;
if(argc!=2){
fprintf(stderr,"Usage: %s \"string of {},\"\n",argv[0]);
return -1;
}
input=argv[1];
for(i=0;input[i]!='\0';i++){
if(input[i]!='{'&&input[i]!='}'&&input[i]!=','){
fprintf(stderr,"Invalid input\n");
return -1;
}
}
if(i>MAX_LEN){
fprintf(stderr,"Too Long input\n");
return -1;
}
if(input[0]!='{'||input[i-1]!='}'){
printf("No Set\n");
return 0;
}
len = i;
sets[0].insert(STATE(1,'{','{'));
for(i=1;i<len;i++){
build_sets_i(i,input[i],i==len-1);
}
#if 0
for(i=0;i<len;i++){
fprintf(stderr,"TRACE %d:\n",i);
STATE_SET::iterator it;
for(it=sets[i].begin();it!=sets[i].end();++it){
fprintf(stderr,"\t%d,%c,%c\n",it->getLeft(),it->getState(),it->getInputChar());
}
}
#endif
STATE_SET::iterator it;
for(it=sets[len-1].begin();it!=sets[len-1].end();++it){
if(it->getLeft()==0){///find a solution for set
break;
}
}
if(it==sets[len-1].end()){
printf("No Set\n");
}else{
printf("Set\n");
///Next show how to treat the set;
printf("%s\n",input);
trace = new char[len+1];
trace[len]='\0';
STATE s=*it;
for(i=len-1;i>0;i--){
trace[i]=s.getInputChar();
s = s.findPrevState(input[i],i-1,i==len-1);
}
trace[0]=s.getInputChar();
printf("%s\n",trace);
delete []trace;
}
}
孩皮妞野 2007-10-29
  • 打赏
  • 举报
回复
卖糕的,谢谢了, tailzhou。

mathe兄好,很佩服老兄的数学功底。很多年不上CSDN了,还在海星老大在的时候就看到你了,问好!
tailzhou 2007-10-29
  • 打赏
  • 举报
回复
2661690 2007-10-29 10:04:28 Accepted 2800 C++ 00:00.08 1016K tailzhou

输出格式错误!

printf("Word# %d: %sSet\n",i,WhatIsThis(0,n-1)==1?"":"No ");
==>
printf("Word #%d: %sSet\n",i,WhatIsThis(0,n-1)==1?"":"No ");
mathe 2007-10-29
  • 打赏
  • 举报
回复
我想,这个题目可以如下考虑
使用动态规划判断,记录[0,k)子串可以形成的状态,状态有下面俩成员:
i) 还有numberLeft个{多余,要求numberLeft>=1
ii) 当前集合的状态,有三个状态'{',',','E':
1. '{': 也就是当前集合还只有{,里面没有任何元素和',',
所以后面如果遇上‘{’,可以numberLeft加1,保持状态'{';也可以numberLeft不变,变为状态'E'
如果后面遇上‘}’,可以numberLeft减1,变为状态'E'(当成});也可以numberLeft不变,变为状态'E'(当成元素)
如果后面遇上‘,’,将状态变成','
2. ',': 也就是当前集合里面最后遇到的是","
所以后面如果遇上‘{’,可以numberLeft加1,变成状态'{';也可以numberLeft不变,变为状态'E'
如果后面遇上‘}’,可以numberLeft减1,变为状态'E'(当成});也可以numberLeft不变,变为状态'E'(当成元素)
如果后面遇上‘,’,将状态保持','
3. 'E': 也就是当前集合最后是一个元素
所以后面如果遇上'{',淘汰这种可能性
如果后面遇上‘}’,将numberLeft减1,变为状态'E'(当成})
如果后面遇上‘,’,将状态变为','
在上面过程中,任何时候如果numberLeft减少到0,这种情况也要淘汰。
知道最后一步如果能够到达一个numberLeft正好是0的状态,那么结果就是集合。
孩皮妞野 2007-10-29
  • 打赏
  • 举报
回复
谢谢C兄,我没辙了才来求救的 :)

顺便说一下,原题链接是
http://acm.zju.edu.cn/show_problem.php?pid=2800

也许我对题目有理解错误?
kaishui_gu 2007-10-29
  • 打赏
  • 举报
回复
觉的LZ给的形式语法不对
kaishui_gu 2007-10-29
  • 打赏
  • 举报
回复
楼主的示例看不懂,谁可以帮忙解析下
示例输入
3
{{{}}
{{},{,,{{}},{},{}}},{{,}},},}}
{{,},{},{,},}}

示例输出
Word #1: Set
Word #2: Set
Word #3: Set
Word #4: No Set
孩皮妞野 2007-10-28
  • 打赏
  • 举报
回复

#include <stdio.h>
#include <set>
#include <iostream>
#include <string>


// using dynamic programming
//

int n; // length of expression
std::string input;

int map[200][200]; // avoid dynamic memory allocation
// S(i,j) : 1 Set
// 2 Non set list
// -1 not yet determined
// 0 Not a set nor a list
inline int& S(int i, int j)
{
return map[i][j];
}


// j>=i guranteed
//
// calculate (if necessary) and return
// 0 if input i to j doesn't form a set nor non-set list
// 1 if input i to j forms a set
// 2 if input i to j forms a non-set list
//
int WhatIsThis(int i, int j)
{
if( S(i,j)==-1) // not filled yet
{
// try to see if it's a set first (note a set is also a list)
// a set must start with '{' end end with '}'
//
if(input[i]=='{' && input[j]=='}'){
if(j<=i+2) // 0 or 1 element set
S(i,j)=1;
else if(WhatIsThis(i+1,j-1)>0)
S(i,j)=1;
}
// if not a set, is it a list?
if( S(i,j)!=1 ){
if(i==j) // Atom is a list by definition
S(i,j)=2;
else{
// if exists k in (i,j) so that input[k]==',' and
// WhatIsThis(i,k-1)>0 &&WhatIsThis(k+1,j)>0, it's
// a non-set list
for(int k=i+1; k<j; ++k){
if(input[k]==',' &&
WhatIsThis(i,k-1)>0 &&
WhatIsThis(k+1,j)>0
){
S(i,j)=2;
break;
}
}
// Finally, neither a set nor a non-set List
if(S(i,j)==-1)
S(i,j)=0;
}
}
}
return S(i,j);
}

void solve(int i)
{
for(int j=0; j<n; ++j)
for(int k=j; k<n; ++k)
map[j][k]=-1;
WhatIsThis(0,n-1);

/* for debug
* print the map
*
for(int ii=0; ii<n; ++ii){
for(int j=0; j<n; ++j){
printf("%2d%c",S(ii,j),j==n-1?'\n':' ');
}
}
*/
printf("Word# %d: %sSet\n",i,WhatIsThis(0,n-1)==1?"":"No ");
}

int main()
{
int question_cnt;
int c;
scanf("%d\n", & question_cnt);
for(int i=0; i<question_cnt; ++i){
std::getline(std::cin,input);
n=input.size();
solve(i+1);
}

}
C1053710211 2007-10-28
  • 打赏
  • 举报
回复
脑袋想爆了也不知道哪里不对,lzAc掉的话一定把错误的原因贴出来呀,奋斗了1个多小时终于放弃了

33,027

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧