【高级算法】禁忌搜索算法解决3SAT问题(C++实现)
转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46440389
近期梳理,翻出了当年高级算法课程做的题目。禁忌搜索算法解决3SAT问题。
吐槽:数学符号怎样在编辑器里打出来啊,为了保留符号,我直接截图了。
1 SAT问题描写叙述
定理4.4.1:
赋值v为使CNF可满足的充要条件是f(x1,x2,…,xm)达到最小值0。
2 禁忌搜索算法
禁忌搜索算法是在局部搜索的过程中引进了贪心选择机制。并利用禁忌表改动邻域,通过构造的候选邻域来控制解得选择和接受过程。
在搜索的过程中,禁忌搜索算法从上一步计算解的候选邻域里选择一个最好的解,即使这个解比上一步得到的解还差,也接受它,同一时候改动禁忌表,以避免该解在禁忌期限内再次被选择。
思路分析例如以下:
1 初始赋值
随机初始化变元值
2 候选邻域的构造:
对于当前的赋值X,从每个非零子句中选出一个变元,全部选出的变元构成一个子变元集SVS。从SVS里选择一个变元,改变它的值,其它的变元值保持不变,得到的解为X的一个邻解。
全部邻解的集合,就构成了候选邻域。降低搜索空间。提高了搜索效率。
3 禁忌表:
禁忌表记录着在近期L次迭代内扰动过得变元,这些变元在当前迭代范围内禁忌扰动。
禁忌表用数组iteration_age[i],i=1,2,…m来表示。iteration_age[i]的值为变元xi被扰动时的迭代序数
变元xi是不是被禁忌:
iteration_age[i]+L>=iteration
禁忌搜索算法解决3SAT问题的伪代码:
算法伪代码:
initcnf();initialiteration_age[] //初始化CNF,禁忌表
iteration = 1;flips = 1 //迭代次数和扰动次数初始化
while(v_cnf(variable)!=0&&iteration< itera_max) //停止准则
SVS[] //从每个非零子句中选出一个变元
flag = 1;i = 0
while(i<|SVS|&&flag==1)do
for j i+1 to |SVS| do
if((candidate(j)-v_cnf(variable))<(candidate(s)-v_cnf(variable))) //从SVS选择f'最小的变元 选择策略
then swap SVS[i] andSVS[j]
if(iteration_age[SVS[i]]+L>=iteration) //假设变元禁忌 if(candidate(i)-v_cnf(variable)<0) //吸引准则
candidate(i) isflipped //接受该变元的扰动
modify iteration_age[] //改动禁忌表
flag=0 flips++
else
i++
else
candidate(i) isflipped //接受该变元的扰动
modify iteration_age[] //改动禁忌表
flag=0 flips++
iteration++;
C++实现代码:
// TS3SAT.cpp : 定义控制台应用程序的入口点。 //
/*********************************
-----------------------------------
禁忌搜索算法解决3SAT问题(C++代码实现)
-----------------------------------
Author:牧之丶 Date:2014年
Email:bzhou84@163.com
**********************************/
#include "stdafx.h"
#include "stdafx.h"
#include <string>
#include <time.h>
#include <fstream>
#include <iostream>
#include <iterator>
using namespace std; const int n=129; //子句个数
const int l=3;
const int m=30; //变元个数
const int L=20; //禁忌表长度
const int N=1000;
int clause[n+5][l+5]; //下标数组
int sign[l*n+1]; //CNF变元符号
int variable[m+1]; //变元数组
//int neighbour[n]; //邻域
int SVS[N]; //子变元集
int vclause[n+5]; //子句的值
int itera_max = 500000;
int iteration_age[m]; //禁忌表
int t;
//int v; //f(x)目标函数 void initcnf() //CNF初始赋值
{
printf("\n");
ifstream in("1.txt");
for(int i =0;i<n+5;i++)
{
for(int j=0;j<=3;j++)
{
clause[i][j]=1;
}
}
for (int i = 1; i <= n; i++)
{
in >> clause[i][1] >> clause[i][2] >> clause[i][3] >> t;
}
//下标变元随机赋值
/*for(int i=0;i<n;i++)
{
for(int j=0;j<l;j++)
{
clause[i][j]=rand()%m+1; //1到m
}
}*/
//各变元符号 0为反 1为正
for(int i=1; i<=n; i++)
for(int j=1; j <= l; j++)
{
//sign[i] == clause[i][j]/abs(clause[i][j]);
if(clause[i][j]/abs(clause[i][j]) == 1)
sign[i]=1;
else
sign[i]=0;
} for(int i=1;i<=m;i++)
{
iteration_age[i]=0;
}
for(int i=0;i<=N;i++)
{
SVS[i]=0;
}
} int v_cnf(int var[]) //f(x)的值
{
int v=0;
for(int i=1;i<=n;i++)
{
vclause[i]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=l;j++)
{
vclause[i] *= (sign[3*(i-1)+j]^var[abs(clause[i][j])]); //各个子句的值
}
v+=vclause[i];
}
return v;
} int candidate(int a) //邻解
{ int var1[m+1];
//memcpy(var1,variable,m+1);
for (int t = 0; t < m+1; t++)
var1[t] = variable[t];
int v=0;
//v=v_cnf();
var1[SVS[a]]=1-var1[SVS[a]];
v=v_cnf(var1);
return v;
}
void tssat() //禁忌搜索
{ srand(double(time(NULL)));
for(int i=1;i<=m;i++) //变元赋值
{
variable[i]=rand()%2; //0到1
}
printf("变元初始赋值为:");
for(int i=1;i<=m;i++)
{
printf("%d ",variable[i]);
}
initcnf();
int iteration=1;
int flips=1;
int c=v_cnf(variable);
printf("初始f(X)=%d ",c);
printf("\n"); while(v_cnf(variable)!=0&&iteration < itera_max)
{ int a=0;
for(int i=0;i<n;i++) //从每个非零子句中选出一个变元
{
if(vclause[i]==1)
{ int svs=abs(clause[i][rand()%l]);
SVS[a]=svs; //选出变元的下标
int pos = 1;
for(int i=0;i<a;i++)
{
if(SVS[a]==SVS[i])
{
pos = 0;
break;
}
}
if (pos == 1)
{
a++;
}
} int flag=1;
int s=0;
while(s<a&&flag==1)
{
for(int j=s+1;j<a;j++)
{
if((candidate(j)-v_cnf(variable))<(candidate(s)-v_cnf(variable))) //选择f'最小的变元
{
/*int temp=candidate(i);
candidate(i)=candidate(j);
candidate(j)=temp;*/
int temp=SVS[s];
SVS[s]=SVS[j];
SVS[j]=temp;
}
}
if(iteration_age[SVS[s]]+L>=iteration) //变元是否禁忌
{
if(candidate(s)-v_cnf(variable)<0) //吸引准则
{
variable[SVS[s]]=1-variable[SVS[s]];
iteration_age[SVS[s]]=iteration;
flag=0;
flips++;
}
else
{ //flag=0;
s++;
}
}
else
{
variable[SVS[s]]=1-variable[SVS[s]];
iteration_age[SVS[s]]=iteration;
flips++;
flag=0;
}
}
iteration++;
}
printf("扰动次数为:%d ",flips);
printf("\n");
printf("变元终于取值为:");
for(int i=0;i<m;i++)
{
printf("%d ",variable[i]);
}
printf("\n");
int v=v_cnf(variable);
printf("终于f(X)=%d\n ",v);
}
} int _tmain(int argc, _TCHAR* argv[])
{ time_t start,end;
start = clock();
tssat();
end = clock(); printf("\n");
printf("执行时间为:%f\n",double(end - start)/(CLOCKS_PER_SEC));
system("pause");
return 0;
return 0;
}
測试全部给出的例子,执行20次可得结果例如以下:
CNF(l=3) |
平均时间 |
成功/失败次数 |
N m |
TS |
TS |
30 129 |
0.8200 |
20/0 |
40 172 |
0.9500 |
20/0 |
50 215 |
0.1500 |
20/0 |
100 430 |
0.2600 |
20/0 |
測试用例(1.txt):http://download.csdn.net/detail/zhoubin1992/8794893
參考文献
[1] 张德富.算法设计与分析(高级教程)[M].国防工业出版社。2007.
【高级算法】禁忌搜索算法解决3SAT问题(C++实现)的更多相关文章
- 【高级算法】遗传算法解决3SAT问题(C++实现)
转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46910079 1 SAT问题描写叙述 命题逻辑中合取范式 (CNF) 的可满足性问 ...
- 原创:TSP问题解决方案-----禁忌搜索算法C实现
本文着重于算法的实现,对于理论部分可自行查看有关资料可以简略参考该博文:http://blog.csdn.net/u013007900/article/details/50379135 本文代码部分基 ...
- 【高级算法】模拟退火算法解决3SAT问题(C++实现)
转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46453761 ---------------------------------- ...
- 【算法】禁忌搜索算法(Tabu Search,TS)超详细通俗解析附C++代码实例
01 什么是禁忌搜索算法? 1.1 先从爬山算法说起 爬山算法从当前的节点开始,和周围的邻居节点的值进行比较. 如果当前节点是最大的,那么返回当前节点,作为最大值 (既山峰最高点):反之就用最高的邻居 ...
- FreeCodeCamp 高级算法(个人向)
freecodecamp 高级算法地址戳这里. freecodecamp的初级和中级算法,基本给个思路就能完成,而高级算法稍微麻烦了一点,所以我会把自己的解答思路写清楚,如果有错误或者更好的解法,欢迎 ...
- js 高级算法 - 动态规划
主要是看了<数据结构与算法>有所感悟,虽然这本书被挺多人诟病的,说这有漏洞那有漏洞,但并不妨碍我们从中学习知识. 其实像在我们前端的开发中,用到的高级算法并不多,大部分情况if语句,for ...
- 禁忌搜索算法TSA 旅行商问题TSP python
import math import random import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot ...
- C++实现禁忌搜索解决TSP问题
C++实现禁忌搜索解决TSP问题 使用的搜索方法是Tabu Search(禁忌搜索) 程序设计 1) 文件读入坐标点计算距离矩阵/读入距离矩阵 for(int i = 0; i < CityNu ...
- 【优化算法】变邻域搜索算法解决0-1背包问题(Knapsack Problem)代码实例 已
01 前言 经过小编这几天冒着挂科的风险,日日修炼,终于赶在考试周中又给大家更新了一篇干货文章.关于用变邻域搜索解决0-1背包问题的代码.怎样,大家有没有很感动? 02 什么是0-1背包问题? 0-1 ...
随机推荐
- [BZOJ 1735] Muddy Fields
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1735 [算法] 二分图最小覆盖 [代码] #include<bits/stdc ...
- bzoj 1191 [ HNOI 2006 ] 超级英雄Hero —— 二分图匹配
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1191 就是二分图匹配的裸题: 注意题目要求是第一次匹配失败就退出!没仔细看题差点丢失1A. ...
- XML案例(使用JAXP进行SAX解析)
1.Book.java package cn.itcast.sax; public class Book { private String name; private String author; p ...
- 0502 php简单了解
准备工作: 安装好wamp,配置站点:apache2.4.9\conf\httpd.conf 注意事项: 1.必须有分号 2.不要有无意义空行,会以空格形式输出. 3.变量,关键字(if,for..) ...
- python 13:数字列表统计方法(min(list)、max(list)、sum(list))
numbers = list(range(1,11)) print(numbers) print(min(numbers)) #获得列表最小值 print(max(numbers)) #获得列表最大值 ...
- PHP操作多进程
在以往的开发项目中,要操作进程就会使用PHP自带的pcntl拓展.但是pcntl存在着许多的不足: pcntl没有提供进程间通信的功能 pcntl不支持重定向标准输入和输出 pcntl只提供了fork ...
- java编程基础篇-------> 从键盘输入一位整数,代表月份,编程判断指定月份属于一年中的哪个季度。如果是 12 月、1 月、2 月,就属于冬季。
从键盘输入一位整数,代表月份,编程判断指定月份属于一年中的哪个季度.如果是 12月.1 月.2 月,就属于冬季:如果是 3 月.4 月.5 月,就属于春季:如果是 6 月.7 月.8 月,就属于夏季: ...
- ie8及其以下版本兼容性问题之响应式
解决办法:引入Respond.js让IE6-8支持CSS3 Media Query 使用方式 参考官方demo:http://scottjehl.github.com/Respond/test/tes ...
- RRDtool入门详解
---------------原创内容,转载请注明出处.<yaoyao0777@Gmail.com>------------ 一.概述 RRDtool(round-robin databa ...
- 时序分析:串匹配-KMP算法
图像处理与模式识别的教科书使用大量的章节来描述空域的模式识别方法.从图像底层特征提取.贝叶斯方法到多层神经网络方法,一般不讨论到对象随时间变化的情况,视频处理应用和在线学习方法使研究对象开始向时域延伸 ...