一、参考资料及问题
命题变元及其否定统称为文字。仅由有限个文字构成的析取式称为简单析取式。
设p、q为二个命题变元
p,q,p∨p,q∨q,¬p∨q, ¬q∨ ¬p,p∨q,p∨ ¬q 称为简单析取式
由有限个简单合取式构成的析取式称为析取范式(disjunctive normal form),简称DNF。
给定一个2DNF,如:,找一个算法,使得它能在多项式时间里判定任一给定的2DNF是否可满足,如果可满足,给每一个变量(如上例中的
,
,
,
)一个真值指派(true或false),使得该2DNF的值为true。
二、程序功能说明
允许用户以一种非常简单的形式输入一个2DNF来进行测试
能够在多项式时间里判断一个2DNF是否可满足。
能够在多项式时间里给出一个可满足的2DNF的真值指派。
三、算法的设计
例如用2DNF 。2DNF可满足问题的多项式时间算法要借助于图论中的知识。下面的规则说明了如何把一个2DNF转化为一个有向图G=<V,E>:
(1)把2DNF的每个变量及这个变量的非都作为图G的顶点。显然若这个2DNF有3个变量,那么将有6个顶点。
(2)有从顶点 指向顶点
的边当且仅当在这个2DNF字句中有子句
。显然每个字句
对应两条有向边:从顶点
指向顶点
的有向边和从顶点
指向
的有向边。
如,对2DNF ,
画出有向图的步骤:
1) 对于在f中出现的变量xi,在G中构造两个顶点和
,
两个顶点用一条边相连。
2) 若子句cj中有nj个文字,则在G中构造一个具有nj个顶点的团。
3) 对于子句cj中出现的每一个文字所对应的顶点(或
),
连一条边到nj-团中的一个顶点(不同的文字必须连到不同的顶点,
故团中每一个顶点都有一条边连到某个文字顶点)。
4) 令k=n+(e.g. k=3+(3-1)+(2-1)=6)。
以上四条显然可以在多项式时间内实现
与之对应的有向图为:
程序总共运用了四个函数计算的数值getMatrixIndex,求取二维数组getAdjacentMatrix的函数,图的遍历函数BFS,讨论是否满足可满足性的函数isSat。
程序代码:
#include <iostream>
#include <cmath>
#include <queue>
#include<windows.h>
using namespace std;
/**********计算赋值的函数***********/
int getMatrixIndex(int x, int varNum)
{
int b = varNum/2;
return (int)abs((abs(x)/x - 1)/2 * b + x) - 1;
}
/****************给数组二维adjacentMatrix赋值****************/
bool ** getAdjacentMatrix(int inputArray[][2], int length, int varNum)
{
bool **adjacentMatrix = new bool *[varNum];
for(int i = 0; i < varNum; i++)
{
adjacentMatrix[i] = new bool[varNum];
for (int j = 0; j < varNum; j++)
{
adjacentMatrix[i][j] = false;
}
}
for (int k = 0; k < length; k++)
{
int row1 = getMatrixIndex(-inputArray[k][0], varNum);
int to1 = getMatrixIndex(inputArray[k][1], varNum);
int row2 = getMatrixIndex(-inputArray[k][1], varNum);
int to2 = getMatrixIndex(inputArray[k][0], varNum);
adjacentMatrix[row1][to1] = true;
adjacentMatrix[row2][to2] = true;
}
cout<<"与图有关的矩阵edges:"<<endl;
for(int i = 0; i < varNum; i++)
{
for (int j = 0; j < varNum; j++)
{
cout<<" "<<adjacentMatrix[i][j];
}
cout<<endl;
}
return adjacentMatrix;
}
/**基于BFS来决定从节点from到节点to是否有一条有向路径,若有的话返回true,否则返回false**/
bool BFS(int from, int to, bool ** adjacentM, int length)
{
bool **status = new bool *[length];
for(int s = 0; s < length; s++)
{
status[s] = new bool[length];
for (int m = 0; m<length; m++)
{
status[s][m] = false;
}
}
queue<int>myQue;
myQue.push(from);
while(!myQue.empty())
{
int beginning = myQue.front();
myQue.pop();
for (int n = 0; n < length; n++)
{
if (adjacentM[beginning][n] == true && status[beginning][n] == false)
{
if (n == to)return true;
myQue.push(n);
}
status[beginning][n] = true;
}
}
return false;
}
/**************判断一个2NF能否满足*****************/
bool isSat(bool **Matrix, int length)
{
for (int l = 1; l<= length/2; l++)
{
if (BFS(getMatrixIndex(l, length), getMatrixIndex(-l, length), Matrix, length)
&& BFS(getMatrixIndex(-l, length), getMatrixIndex(l, length), Matrix, length))
{
return false;
}
}
return true;
}
/*************主函数***************/
int main()
{
system("color FC");
int inputArray[][2] = {
{ 1, 2},
{-1, -2},
{-4, -5},
{-2, 3},
{ 3, 4},
{-3, 5},
{ 4, -3}
} ;
cout<<"输入数组为:"<<endl;
for(int i=0;i<7;i++)
{
for(int j=0;j<2;j++)
cout<<'/t'<<inputArray[i][j];
cout<<endl;
}
bool **matrix = getAdjacentMatrix(inputArray, 7, 10);
if (isSat(matrix, 10))
cout<<endl<<"两个文字的析取范式是可满足"<<endl;
else
cout<<endl<<"两个文字的析取范式不可满足"<<endl;
return 0;
}
结果分析: