Las vegas解3SAT问题

本文介绍了一种基于Las Vegas算法求解3SAT问题的方法,并提供了详细的算法流程及C++实现代码。通过随机重复直到成功的方式找到满足条件的赋值方案。

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
回溯对时间没有改进,有空在看看.





                
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值