禁忌搜尋演算法解決3SAT問題(C++代碼實現)

來源:互聯網
上載者:User

標籤:進階演算法   禁忌搜尋   c++   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 : 定義控制台應用程式的進入點。//#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;}

參考文獻

[1]  張德富.演算法設計與分析(進階教程)[M].國防工業出版社,2007.


禁忌搜尋演算法解決3SAT問題(C++代碼實現)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.