构造法 poj3295

Tautology

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 9580   Accepted: 3640

Description

WFF ‘N PROOF is a logic game played with dice. Each die has six faces representing some subset of the possible symbols K, A, N, C, E, p, q, r, s, t. A Well-formed formula (WFF) is any string of these symbols obeying the following rules:

  • p, q, r, s, and t are WFFs
  • if w is a WFF, Nw is a WFF
  • if w and x are WFFs, Kwx, Awx, Cwx, and Ewx are WFFs.

The meaning of a WFF is defined as follows:

  • p, q, r, s, and t are logical variables that may take on the value 0 (false) or 1 (true).
  • K, A, N, C, E mean and, or, not, implies, and equals as defined in the truth table below.
Definitions of K, A, N, C, and E
     w  x   Kwx   Awx    Nw   Cwx   Ewx
  1  1   1   1    0   1   1
  1  0   0   1    0   0   0
  0  1   0   1    1   1   0
  0  0   0   0    1   1   1

tautology is a WFF that has value 1 (true) regardless of the values of its variables. For example, ApNp is a tautology because it is true regardless of the value of p. On the other hand, ApNq is not, because it has the value 0 for p=0, q=1.

You must determine whether or not a WFF is a tautology.

Input

Input consists of several test cases. Each test case is a single line containing a WFF with no more than 100 symbols. A line containing 0 follows the last case.

Output

For each test case, output a line containing tautology or not as appropriate.

Sample Input

ApNp
ApNq
0

Sample Output

tautology
not

这道题的意思:用字符串的形式给你一个逻辑表达式,判断是否为永真式,逻辑变量只有那五个小写字母

这是我的代码,没什么价值

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const char ch[5]={‘p‘,‘q‘,‘r‘,‘s‘,‘t‘};
char a[120];
int rep[255];
 int f[120];
int len;
void printrep(){
    for(int i=0;i<5;i++){
        printf("%c%d ",ch[i],rep[ch[i]]);
    }
    puts("");
}
bool isnum(char ch1){
    for(int i=0;i<5;i++)if(ch1==ch[i])return true;
    return false;
}
bool dfs(int ind){
    if(ind<5){if(!dfs(ind+1))return false;rep[ch[ind]]=1;if(!dfs(ind+1))return false;rep[ch[ind]]=0;return true;}
    memset(f,0,sizeof(f));
    int index=0;
    for(int i=len-1;i>=0;i--){
        if(isnum(a[i])){
            f[index++]=rep[a[i]];
        }
        else {
            if(a[i]==‘K‘){
                f[index-2]=f[index-2]&f[index-1];
                index--;
            }
            if(a[i]==‘A‘){
                  f[index-2]=f[index-2]|f[index-1];
                index--;
            }
            if(a[i]==‘N‘){
                f[index-1]=1^f[index-1];
            }
            if(a[i]==‘C‘){
                f[index-2]=((1^f[index-1])|f[index-2]);
                index--;
            }
            if(a[i]==‘E‘){
                f[index-2]=1^(f[index-2]^f[index-1]);
                index--;
            }
        }
    }
    if(f[index-1]==0)return false;
    return true;
}
int main()
{
    while(scanf("%s",a)==1&&strcmp(a,"0")){
        memset(rep,0,sizeof(rep));
        len=strlen(a);
        if(dfs(0)){
            puts("tautology");
        }
        else {
            puts("not");
        }
    }
    return 0;
}

int ind()//这位大神这么做的看起来清洁干净
{
    char ch=s[l++];//把整个堆栈过程和变量分开看了
    printf("");

    switch(ch)
    {
    case ‘p‘:
    case ‘q‘:
    case ‘r‘:
    case ‘s‘:
    case ‘t‘:
        return state[ch];
        break;
    case ‘K‘:
        return ind()&ind();
        break;
    case ‘A‘:
        return ind()|ind();
        break;
    case ‘N‘:
        return !ind();
        break;
    case ‘C‘:
        return !ind()|ind();
        break;
    case ‘E‘:
        return ind()==ind();
        break;
    }
}

还可以字符替换,不贴了,可以增强直观,反正数据不大

讨论区看到的

WA来自那些递归下降求解的代码.
第一种情况,使用|| 和 &&:
例如s为所给串
int getval()
{
	switch(s[c_s++])
	{
	case ‘p‘: return (value & (1 << 0))? 1:0;
	case ‘q‘: return (value & (1 << 1))? 1:0;
	case ‘r‘: return (value & (1 << 2))? 1:0;
	case ‘s‘: return (value & (1 << 3))? 1:0;
	case ‘t‘: return (value & (1 << 4))? 1:0;

	case ‘K‘: return getval() && getval();
	case ‘A‘: return getval() || getval();
	case ‘N‘: return !getval();
	case ‘C‘: return !getval() || getval();
	case ‘E‘: return getval() == getval();
	}
}
这种情况简单,大家知道短路求值吧,先对 ||左边的表达式求值,如果非0,则不会对右边的表达式求值,&&同理,如果左边为0,不会对右边求值,这样下标就不会按照事先设想的增加
第二种情况,使用&和|:
int getval()
{
	switch(s[c_s++])
	{
	case ‘p‘: return (value & (1 << 0))? 1:0;
	case ‘q‘: return (value & (1 << 1))? 1:0;
	case ‘r‘: return (value & (1 << 2))? 1:0;
	case ‘s‘: return (value & (1 << 3))? 1:0;
	case ‘t‘: return (value & (1 << 4))? 1:0;

	case ‘K‘: return getval() & getval();
	case ‘A‘: return getval() | getval();
	case ‘N‘: return !getval();
	case ‘C‘: return !getval() | getval();
	case ‘E‘: return getval() == getval();
	}
}
首先这段代码用G++会AC,C++会WA,说明此段代码依赖编译器,是未定义的代码
错误原因: C语言对表达式的求值顺序不是明确规定的,而G++是从左从左向右求值,C++则正好相反,比如: getval() | getval() G++先对左边的getval()求值,而C++则先对右边的getval()求值,也就会导致对s的访问顺序不会按预先的步骤进行,所以用G++会ac,C++会WA掉
正确的写法,去掉那些跟依赖求值顺序的代码(好习惯),分别求值,用两个临时变量保存,这样G++和C++都AC了:
int getval()
{       int temp1, temp2;
	switch(s[c_s++])
	{
	case ‘p‘: return (value & (1 << 0))? 1:0;
	case ‘q‘: return (value & (1 << 1))? 1:0;
	case ‘r‘: return (value & (1 << 2))? 1:0;
	case ‘s‘: return (value & (1 << 3))? 1:0;
	case ‘t‘: return (value & (1 << 4))? 1:0;

	case ‘K‘: temp1 = getval(); temp2 = getval(); return temp1 & temp2;
	case ‘A‘: temp1 = getval(); temp2 = getval(); return temp1 | temp2;
	case ‘N‘: return !getval();
	case ‘C‘: temp1  = !getval(); temp2 = getval(); return temp1 | temp2;
	case ‘E‘: temp1 = getval(); temp2 = getval(); return temp1 == temp2;
	}
}
时间: 2024-11-05 21:42:45

构造法 poj3295的相关文章

利用子集构造法实现NFA到DFA的转换

概述 NFA非有穷自动机,即当前状态识别某个转换条件后到达的后继状态不唯一,这种自动机不便机械实现,而DFA是确定有限状态的自动机,它的状态转换的条件是确定的,且状态数目往往少于NFA,所以DFA能够比较方便的机械实现且识别能力方面也和NFA相当.本次实验采用子集构造法来实现不带空弧的由NFA到DFA的转换. 子集构造法的算法如下: 设NFA为M=(K,Σ,f,S0,Z),则构造相应的DFA  M′=(Q,Σ,f′,I0,F)①取I0=S0:②对于状态集Q中任一尚未标记的状态qi={Si1,Si

生成子集 (增量构造法)

使用增量构造法可以构造出升序数组arr的不重复子集,并且按字典序排序 #include<bits/stdc++.h> using namespace std; int arr[16]; inline void print_subset(int *index, int cur, int n)///cur值这里可以理解为在这个堆栈层子集的集合数 { for(int i=0; i<cur; i++) {printf("%d ", arr[index[i]]);} if(cu

【算法竞赛入门经典】7.3子集生成【增量构造法】【位向量法】【二进制法】

7.3.1增量构造法 思路:一次选出一个元素放到集合中.自己对于递归的理解还是不够,这里虽然没有明确给出递归停止条件,但是如果无法继续添加元素,就不会再继续递归,然后就是我头疼的回溯啦. #include<stdio.h> int num[4],n; void A(int n,int *a,int ans) { for(int i = 0; i < ans; i ++)//打印当前元素 printf("%d ",a[i]); printf("\n"

子集生成——增量构造法+位向量法+二进制法

1.增量构造法: 原理图: 1 // 此算法仅用于输出下标,实际运用应输入另一个数组来进行数据的储存 2 #include <bits/stdc++.h> 3 using namespace std; 4 typedef long long ll; 5 typedef unsigned long long ull; 6 #define INF 0X3f3f3f3f 7 const ll MAXN = 1e3 + 7; 8 const ll MOD = 1e9 + 7; 9 int a[10];

后缀数组 DC3构造法 —— 详解

学习了后缀数组,顺便把DC3算法也看了一下,传说中可以O(n)复杂度求出文本串的height,先比较一下倍增算法和DC3算法好辣. DC3 倍增法 时间复杂度 O(n)(但是常数很大)   O(nlogn)(常数较小) 空间复杂度   O(n)    O(n) 编程复杂度    较高   较低 由于在时间复杂度上DC3的常数比较大,再加上编程复杂度比较高,所以在解决问题的时候并不是最优选择.但是学到了后缀数组还是补充一下的好点. DC3算法的实现: 1:先把文本串的后缀串分成两部分,第一部分是后

Codeforces Round #276 (Div. 2)C. Bits(构造法)

这道题直接去构造答案即可. 对于l的二进制表示,从右到左一位一位的使其变为1,当不能再变了(再变l就大于r了)时,答案就是l. 这种方法既可以保证答案大于等于l且小于等于r,也可以保证二进制表示时的1最多. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include&l

uva1605 - Building for UN(构造法)

这道题构造出的结果很妙,考察思维能力.就两层,每层都n*n个格子,第一层第i行都放国家i,第二层第j列都放国家j. 需要注意的是ASCII中A至Z在a至z的前面(数字小),而且它们两组不挨着.所以需要char c(int i)这个函数. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<map>

uva120 Stacks of Flapjacks (构造法)

这个题没什么算法,就是想出怎么把答案构造出来就行. 思路:越大的越放在底端,那么每次就找出还没搞定的最大的,把它移到当前还没定好的那些位置的最底端,定好的就不用管了. 这道题要处理好输入,每次输入的一行中是带空格的,以换行符结束一组数据的输入,那么用getline()函数.再用stringstream(这个可以自动转格式),非常方便的就处理了输入的问题.另外注意max_element和min_element都是左闭右开的. #include<iostream> #include<cstd

POJ 3295-Tautology(构造法+栈)

Tautology Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9936   Accepted: 3774 Description WFF 'N PROOF is a logic game played with dice. Each die has six faces representing some subset of the possible symbols K, A, N, C, E, p, q, r, s,