Las Vegas算法流程:
Repeat3SAT(I)
1 repeat
2 3SATLV(I,X,success)
3 until success
4 return x
解决3SAT问题需要用到小技巧,假定有m个变量,k=1~m,逐个运行:
xValue[k] = FALSE;//预赋值FALSE
falseNum = CaluteTrueNum();//所有子句中满足的个数,重点在这个函数。
xValue[k] = TRUE;////预赋值TRUE
trueNum = CaluteTrueNum();//所有子句中满足的个数,重点在这个函数。
if ((falseNum < 0) && (trueNum < 0))
return false;//falseNum == -1 &&trueNum == -1表示至少其中一个子句false,k重新开始扫描;
else if(falseNum < 0)
xValue[k] = TRUE;//xValue[k] = FALSE导致其中至少一个子句false,所以该变量赋值取反;
else if (trueNum < 0)
xValue[k] = FALSE;//xValue[k] =TRUE导致其中至少一个子句false,所以该变量赋值取反;
else
xValue[k] = GetrandTF();//xValue[k] = TRUE 或者 xValue[k] = FALSE都没有使子句false,则根据分别满足的子句个数随机;
Las Vegas+回溯算法C++代码如下:
<pre name="code" class="cpp"><pre name="code" class="cpp">// 3SAT.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include"stdlib.h"
#include <algorithm>
#include <vector>
#include<math.h>
#include<time.h>
#include <iostream>
#include <fstream>
#include<ctime>
#define PRINTF_DEBUG printf
//#define PRINTF_DEBUG //
//#define USE_BACKTRACK//宏打开表示结合回溯算法。
#define RETURN_POSITIVE_VALUE(x) ((x >= 0)?x:(-x))
#define TRUE 1
#define FALSE 2
int m,n,l=3;//1. m=3(变元的个数),n=5(子句的个数),l=3(子句的长度)
int input[430][4];//start from 0
bool input_delete[430];//start from 0
int xValue[201] = { 0 };
int trueNum = 0;//true counter;
int falseNum = 0;//false counter
int stopLV = 0;
void SetXvalueZero(void )
{
<span style="white-space:pre"> </span>for (int i = 1; i <= m; i++)
<span style="white-space:pre"> </span>xValue[i] = 0;
<span style="white-space:pre"> </span>for (int i = 0; i < n; i++)
<span style="white-space:pre"> </span>input_delete[i] = false;
}
void checkAndDelete(void)
{
<span style="white-space:pre"> </span>for (int j = 0; j < n; j++)//calulate whole sentence
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>int count_tt1 = 0;
<span style="white-space:pre"> </span>int count_tt2 = 0;
<span style="white-space:pre"> </span>for (int i = 0; i < l; i++)//caculate every sentence
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>int index = RETURN_POSITIVE_VALUE(input[j][i]);
<span style="white-space:pre"> </span>if (((xValue[index] == TRUE) && (input[j][i] < 0)) || \
<span style="white-space:pre"> </span>((xValue[index] == FALSE) && (input[j][i] > 0)))
<span style="white-space:pre"> </span>count_tt1++;
<span style="white-space:pre"> </span>if (((xValue[index] == TRUE) && (input[j][i] > 0)) || \
<span style="white-space:pre"> </span>((xValue[index] == FALSE) && (input[j][i] < 0)))
<span style="white-space:pre"> </span>count_tt2++;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>if ((count_tt1 == 2) && (count_tt2 == 0))
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>for (int i = 0; i < l; i++)//caculate every sentence
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>int index = RETURN_POSITIVE_VALUE(input[j][i]);
<span style="white-space:pre"> </span>if (xValue[index] == 0)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if (input[j][i] > 0)
<span style="white-space:pre"> </span>xValue[index] = TRUE;
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>xValue[index] = FALSE;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>input_delete[j] = true;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if (count_tt2 > 0)
<span style="white-space:pre"> </span>input_delete[j] = true;
<span style="white-space:pre"> </span>}
}
bool satisfy(void)//flag: 返回当前[k] =true 赋值时子句满足的个数;false同理;trick:是否用技巧
{
<span style="white-space:pre"> </span>for (int j = 0; j < n; j++)//calulate whole sentence
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if (input_delete[j] == false)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>int count_tt = 0;
<span style="white-space:pre"> </span>for (int i = 0; i < l; i++)//caculate every sentence
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>int index = RETURN_POSITIVE_VALUE(input[j][i]);
<span style="white-space:pre"> </span>if (((xValue[index] == TRUE) && (input[j][i] < 0)) || \
<span style="white-space:pre"> </span>((xValue[index] == FALSE) && (input[j][i] > 0)))
<span style="white-space:pre"> </span>count_tt++;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>if (count_tt == 3)
<span style="white-space:pre"> </span>return false;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return true;
}
int CaluteTrueNum(void)
{
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>if (satisfy())
<span style="white-space:pre"> </span>{ int count_tt = 0;
<span style="white-space:pre"> </span>for (int j = 0; j < n; j++)//calulate whole sentence
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>//if (input_delete[j] == false)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>for (int i = 0; i < l; i++)//caculate every sentence
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>int index = RETURN_POSITIVE_VALUE(input[j][i]);
<span style="white-space:pre"> </span>if (((xValue[index] == TRUE) && (input[j][i] > 0)) || \
<span style="white-space:pre"> </span>((xValue[index] == FALSE) && (input[j][i] < 0)))
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>count_tt++;
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return count_tt;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return -1;
}
int CaluteTrueNum1(void)
{
<span style="white-space:pre"> </span>int count_tt = 0;
<span style="white-space:pre"> </span>for (int j = 0; j < n; j++)//calulate whole sentence
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>for (int i = 0; i < l; i++)//caculate every sentence
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>int index = RETURN_POSITIVE_VALUE(input[j][i]);
<span style="white-space:pre"> </span>if (((xValue[index] == TRUE) && (input[j][i] > 0)) || \
<span style="white-space:pre"> </span>((xValue[index] == FALSE) && (input[j][i] < 0)))
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>count_tt++;
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return count_tt;
}
int GetrandTF(void)
{
<span style="white-space:pre"> </span>long i = rand() * (trueNum + falseNum) / RAND_MAX;
<span style="white-space:pre"> </span>int retValue = TRUE;
<span style="white-space:pre"> </span>if (i <= trueNum)
<span style="white-space:pre"> </span>retValue = TRUE;
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>retValue = FALSE;
<span style="white-space:pre"> </span>PRINTF_DEBUG("random = %d trueNum = %d falseNum = %d (trueNum + falseNum) = %d\n", i, trueNum, falseNum, (trueNum + falseNum));
<span style="white-space:pre"> </span>return retValue;
}
void Backtrack(int k)
{
<span style="white-space:pre"> </span>if (k > m)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>;;// return true;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>xValue[k] = FALSE;
<span style="white-space:pre"> </span>if (satisfy())
<span style="white-space:pre"> </span>Backtrack(k + 1);
<span style="white-space:pre"> </span>xValue[k] = TRUE;
<span style="white-space:pre"> </span>if (satisfy())
<span style="white-space:pre"> </span>Backtrack(k + 1);
<span style="white-space:pre"> </span>}
}
bool LV(void)
{
<span style="white-space:pre"> </span>SetXvalueZero();
<span style="white-space:pre"> </span>for (int k = 1; k < stopLV; k++)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>PRINTF_DEBUG("########## k = %d\n", k);
<span style="white-space:pre"> </span>if (xValue[k] == 0)
<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>xValue[k] = FALSE;
<span style="white-space:pre"> </span>falseNum = CaluteTrueNum();
<span style="white-space:pre"> </span>xValue[k] = TRUE;
<span style="white-space:pre"> </span>trueNum = CaluteTrueNum();
<span style="white-space:pre"> </span>if ((falseNum < 0) && (trueNum < 0))
<span style="white-space:pre"> </span>return false;
<span style="white-space:pre"> </span>else if(falseNum < 0)
<span style="white-space:pre"> </span>xValue[k] = TRUE;
<span style="white-space:pre"> </span>else if (trueNum < 0)
<span style="white-space:pre"> </span>xValue[k] = FALSE;
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>xValue[k] = GetrandTF();
<span style="white-space:pre"> </span>checkAndDelete();
<span style="white-space:pre"> </span>PRINTF_DEBUG("xValue[%d] = %d\n", k, xValue[k]);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
<span style="white-space:pre"> </span>srand((unsigned)time(NULL));
<span style="white-space:pre"> </span>ofstream fout("output.txt");
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>for (int fileNum = 1; fileNum <= 1; fileNum++)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>char str[10];
<span style="white-space:pre"> </span>sprintf(str, "3SAT\\%d.txt", fileNum);
<span style="white-space:pre"> </span>freopen(str, "r", stdin);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>int i = 0;
<span style="white-space:pre"> </span>while (scanf("%d%d%d%d", &(input[i][0]), &(input[i][1]), &(input[i][2]), &(input[i][3])) != EOF)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>m = max(max(max(max(abs(input[i][0]), abs(input[i][1])), abs(input[i][2])), abs(input[i][3])), m);
<span style="white-space:pre"> </span>i++;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>n = i;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>stopLV = m + 1;
#ifdef USE_BACKTRACK
<span style="white-space:pre"> </span>stopLV = m - 10;
#else
<span style="white-space:pre"> </span>stopLV = m + 1;
#endif
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>clock_t now_time = clock(); //long t1 = time(NULL);
<span style="white-space:pre"> </span>while (LV() == false);
<span style="white-space:pre"> </span>Backtrack(stopLV);
<span style="white-space:pre"> </span>clock_t finish = clock();
<span style="white-space:pre"> </span>long t = finish - now_time; //前后之差即程序运行时间 (ms)
<span style="white-space:pre"> </span>PRINTF_DEBUG("variable_num = %d\nsentence_num = %d\nstopLV = %d\n", m, n, stopLV);
<span style="white-space:pre"> </span>PRINTF_DEBUG("satisfy sentence num = %d\n", CaluteTrueNum1());
<span style="white-space:pre"> </span>PRINTF_DEBUG("consume time = %d\n", t);
<span style="white-space:pre"> </span>PRINTF_DEBUG("variable_num = %d\nsentence_num = %d\nstopLV = %d\n", m, n, stopLV);
<span style="white-space:pre"> </span>fout << str << " " << m << " " << n << " " << t<< endl; // fout用法和cout一致, 不过是写到文件里面去
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return 0;
}
程序运行时间:file x_num clause_num consume_time(ms)
1.txt 30 129 5
2.txt 30 129 2
3.txt 30 129 6
4.txt 40 172 4
5.txt 40 172 5
6.txt 40 172 11
7.txt 50 215 45
8.txt 50 215 5
9.txt 50 215 52
10.txt 100 430 13001
11.txt 100 430 1412
12.txt 100 430 1695
回溯对时间没有改进,有空在看看.
本文介绍了一种基于Las Vegas算法求解3SAT问题的方法,并提供了详细的算法流程及C++实现代码。通过随机重复直到成功的方式找到满足条件的赋值方案。
791

被折叠的 条评论
为什么被折叠?



