poj-3295 Tautology

Tautology
构造法。。虽然我也不知道什么叫构造法
https://vjudge.net/problem/POJ-3295 题目链接
题目大意:
给定一个关系式,判断是否为重言式(永真式)
给定数据由一个字符串组成,其中包括,K A N C E     p q r s t
其中K代表与运算  A代表或运算 N代表取反 C代表implies//Cab = (!a || b)    E代表同或,,
然后小写字母代表逻辑变量
例如:
Np  就是对于逻辑变量p取反
ApNp即为p || !p 即为重言式

题目要求: 
对于给定的表达式,逻辑变量可以取 0 1 ,如果一个逻辑表达式不管逻辑变量如何取值,表达式
都为重言式,那么就是个Tautology 否则输出not

大概意思在所有的可能的表达式取法种,都为重言式,输出Tautology 否则输出 not

note: 如果一个表达式种多次出现了q 或者其他任意字母,那么他们的逻辑取值必须一样
//真坑了我好大一会

例如题目给定的第一个Sample 
ApNp  即为 p || !p  肯定是重言式, 所以打印Tautology

思路:

将其中所有的逻辑变量全部替换成0 和 1 把所有情况都找一下, 如果全为重言式,即为Tautology
否则not

刚开始递归等各种方法来找到所有状态/情况  发现超时,最后解决方案:
题目最多给了5个逻辑变量,也就是说最多有32种情况
列举出来,然后挨个尝试

代码

#include <iostream>
#include <stack>
#include <cstring>

std::string str; //保存输入字符串
int len; //字符串长度
bool res = true; //判定结果
int qrr[5]; //5个逻辑变量的情况

bool judge(char a)  //因为数据含有大写和小写,用函数判断一下
{
    if(a >= 'A' && a <= 'Z') return true;
    return false;
}
/*

vj函数,判断表达式最终结果,
用到了栈,
从字符串最后开始找,如果是逻辑变量就进栈,不是的话就看是单目还是双目运算符,然后算出结果栈,
到最后栈里仅存一个最后表达式结果
*/

bool vj(std::string a)  //判断
{ 
    int temp = 0;
    std::stack<int> ar; //栈
    for(int i = len - 1; i >= 0; --i)
    {
	if(!judge(a[i])) ar.push(a[i]-'0');  //如果是逻辑变量,进栈
	else
	{                           //不是的话
	    char ch = a[i];
	    if(ch == 'N')  //下面就是各个运算符
	    {
		int front = ar.top();
		ar.pop();
		ar.push(!front);
	    }
	    else if(ch == 'K')
	    {
		int front1 = ar.top();
		ar.pop();
		int front2 = ar.top();
		ar.pop();
		ar.push(front1 && front2);
	    }
	    else if(ch == 'A')
	    {
		int front1 = ar.top();
		ar.pop();
		int front2 = ar.top();
		ar.pop();
		ar.push(front1 || front2);
	    }
	    else if(ch == 'C')
	    {
		int front1 = ar.top();
		ar.pop();
		int front2 = ar.top();
		ar.pop();
		ar.push(!front1 || front2);
	    }
	    else if(ch == 'E')
	    {
		int front1 = ar.top();
		ar.pop();
		int front2 = ar.top();
		ar.pop();
		ar.push((front1 == front2));
	    }
	}
    }
    temp = ar.top(); //表达式最后结果
    ar.pop();
    return temp; 
}

void dfs(std::string arr, bool skip, int q[]) 
{
    if(skip) return; //剪枝,当有一个不为重言式的时候,剩下都没必要判断了,结果直接not
    for(int i = 0; i < len; ++i) //把其中的逻辑变量替换成0 1
    {
	if(str[i] == 'p') arr[i] = q[0] + '0';
	else if(str[i] == 'q') arr[i] = q[1] + '0';
	else if(str[i] == 'r') arr[i] = q[2] + '0';
	else if(str[i] == 's') arr[i] = q[3] + '0';
	else if(str[i] == 't') arr[i] = q[4] + '0';
    }
	if(!vj(arr)) //判断
	{
	    res = false;
	    skip = true;
	}
	return;
}

void init(int i, int value) //递归列举32种状态
{
    if(!res) return;
    qrr[i] = value;
    if(i > 3) //当i == 4 就是某一种情况找完了,开始去看结果是否为重言式
    {
	dfs(str, false, qrr); //判断函数
	return;
    }
    init(i+1, 0);
    init(i+1, 1);
    return;
}



int main()
{
    while(std::cin >> str && str[0] != '0') //循环输入
    {
	res = true; //set初始值
	memset(qrr,0, sizeof qrr); //这个其实写不写都行
	len = str.size(); //保存长度
	init(0, 0); 
	init(0, 1);//从第一个的两种情况开始遍历所有的32种情况
	if(res) std::cout << "tautology" << std::endl;
	else std::cout << "not" << std::endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值