1.题目大意: http://acm.hnu.cn/online/?action=problem&type=show&id=12022&courseid=186
在布尔逻辑中,析取范式(DNF)是逻辑公式的标准化(或规范化),它是合取子句的析取。一个逻辑公式被认为是 DNF 的,当且仅当它是一个或多个文字的一个或多个合取的析取。同合取范式(CNF)一样,在 DNF 中的命题算子是与、或和非。非算子只能用做文字的一部分,这意味着它只能领先于命题变量。
简单来说,析取范式是一些字句的逻辑或,而它的字句是一个合取范式;合取范式是一些字句的逻辑或,而它的字句是一个析取范式。
本题中,逻辑树最深的节点是一个逻辑与,然后逻辑的与和或在每层交替出现。从最下层为一数起,奇数层是逻辑与,偶数层是逻辑或。
假设A=False, B=True, C=False, D=True, E=False那么这颗bool树的最终结果为false
上图输入数据形式为:((F(TF))(TF))
题解:既然是一颗树,那么很自然的会想到要建一棵树,可是数据给的很恶心,要想建好一棵树然后再来求解貌似不太好实现(不信你可以试试,反正我的失败了)。
后来灵光一闪,让我看出了端倪,树不是一层一层的吗,深搜不也是一层一层的吗,我每次遇到一个‘(’号,就进行一次深搜,遇到‘)’便结束搜索。遇到T或者F便先保存,最后根据该次搜索的深度来决定是用或操作还是用与操作。
写好提交,果断AC,爽歪歪啊
View Code
#include<iostream>
#include<string>
using namespace std;
char str[32005];
int len;
int visit[32005];
int dfs(int s,int dep)
{
int i,j,ans,v[3],num[3],k,temp;
k=0;
memset(v,0,sizeof(v)); //由于bool只有0和1,结果只可能有两个,对结果判重
for(i=s;i<len;i++)
{
if(!visit[i])
{
visit[i]=1;
if(str[i]=='(') //深度加一
{
temp=dfs(i+1,dep+1); //在下一层中计算结果并返回
if(!v[temp])
{
v[temp]=1;
num[k++]=temp;
}
}
else if(str[i]=='T' || str[i]=='F') //本身深度,直接保存结果
{
if(str[i]=='T')
temp=1;
else if(str[i]=='F')
temp=0;
if(!v[temp])
{
v[temp]=1;
num[k++]=temp;
}
}
else if(str[i]==')') //该深度计算结束
{
break;
}
}
}
ans=num[0];
if(dep%2==0) //偶数层用与操作
{
for(j=1;j<k;j++)
{
ans=ans&num[j];
}
}
else //奇数层用或操作
{
for(j=1;j<k;j++)
{
ans=ans|num[j];
}
}
return ans;
}
int main()
{
int t=1,dd,i,ans,maxdd;
freopen("e:\\in.txt","r",stdin);
while(scanf("%s",str)!=EOF)
{
if(strcmp(str,"()")==0)
break;
memset(visit,0,sizeof(visit));
len=strlen(str);
dd=0;maxdd=0; //计算最大深度
for(i=0;i<len;i++)
{
if(str[i]=='(')
{
dd++;
if(dd>maxdd)
maxdd=dd;
}
else if(str[i]==')')
dd--;
}
if(maxdd%2==0) //由于题目要求最后一层深度要用与操作,而我的想法是深搜时偶数层相与奇数层相或,所以必须人工判别
{
ans=dfs(0,0);
if(ans==0)
{
printf("%d. false\n",t++);
}
else
{
printf("%d. true\n",t++);
}
}
else
{
ans=dfs(0,1);
if(ans==0)
{
printf("%d. false\n",t++);
}
else
{
printf("%d. true\n",t++);
}
}
}
return 0;
}