拟人退火算法解3SAT
一、问题描述
3-SAT是SAT问题的一个特殊例子,当所有子句都刚好包含三个变量时,此类问题叫3-SAT问题。该问题相对于SAT问题,看似复杂度降低,但仍为NPC问题。由于其苛刻的条件(子句由三个变量组成),使其更容易归约到其他问题,因此比起SAT问题,3-SAT在NPC问题的证明中用得更加广泛。
二、算法
模拟退火算法:模拟退火算法来源于固体退火原理,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。根据Metropolis准则,粒子在温度T时趋于平衡的概率为e-ΔE/(kT),其中E为温度T时的内能,ΔE为其改变量,k为Boltzmann常数。用固体退火模拟组合优化问题,将内能E模拟为目标函数值f,温度T演化成控制参数t,即得到解组合优化问题的模拟退火算法:由初始解i和控制参数初值t开始,对当前解重复“产生新解→计算目标函数差→接受或舍弃”的迭代,并逐步衰减t值,算法终止时的当前解即为所得近似最优解,这是基于蒙特卡罗迭代求解法的一种启发式随机搜索过程。退火过程由冷却进度表(Cooling Schedule)控制,包括控制参数的初值t及其衰减因子Δt、每个t值时的迭代次数L和停止条件S。
拟人退火算法:在组合优化领域里, 当算法搜索到局部极小点时, 一般来说, 就不再往下搜索了。 但是对于 SAT 问题, 就这样停止搜索是不可取的, 其原因在于我们只对 SA T 问题的全局最优点感兴趣。 因为只有全局最优点才能回答该问题是否可满足。 因此我们必须采取有效的策略尽可能的避免陷入局部极小点, 或者到了局部极小点, 能够有效地跳出。 人类在长期的实践中, 积累了丰富的经验, 受他们启发, 我们可以找到一些解决问题的方法。 我们把从人类社会或自然现象中学习到的经验和方法称之为拟人策略。
我们知道, SA 算法能否找到 E (X ) 的全局最优解,取决于 T 0 是否足够高和 T 0 下降得是否足够慢,而这些正好与计算时间相反。虽然合理选择参数可以使得算法的实现只需问题规模的多项式时间,但是随着问题规模的增大,所需时间也随之增长,合理选择参数并不能从根本上提高算法的效率。怎样合理地产生状态 X 1,才是提高效率的关键。为了提高退火过程的效率,根据 SAT 问题的特点,我们提出如下拟人策略,即在每一个迭代步对每个非零子句都随机选择一个变元,将其取反, 来合理地产生状态X 1, 当然, 这里我们必须注意不能选择重复的变元,即在一个子句里随机选择一个变元后, 即使该变元再在其它非零子句里出现, 也不能被选择。 这就像一所学校最初制定一项分配政策, 总有满意和不满意的单位, 然后根据具体情况, 修改令某个单位不满意的一条规则, 使其满意。 当然这条规则在一个时期应统一, 不能这个单位一套, 对别的单位又是另一套。这样才能成为规则, 政策也才得以实施。 该策略可以避免盲目搜索以及减少陷入局部极小的机会, 而且具有一定的并行性。 此外, 给定一个具体的退火机制后, SA 算法并不保证能够找到全局最优点, 例如在SA T 问题里, 能找到一组赋值, 使它满足所有的子句。 前面说过, 我们只对 SA T 问题的全局最优点感兴趣, 当搜索过程陷入局部陷阱时, 就需要某种策略使搜索过程能够跳出, 从而使搜索过程尽可能的找到全局最优。
为了显示采用拟人策略的效果,我们将提出的PA 算法与改进前的 SA 算法作了比较。后者在每一个迭代步只随机选择一个变元,退火结束后, 如没有达到全局最
PA( ) 1 choose an initial solution X0 randomly 2 give an initial temperature T0, X<-X0, T<- T0 3 loop:while the stop criterion is not yet satisfied do 4 for i<- 1 to L do 5 Pick a solution X’ ∈ N(X) randomly 6 △f <-f(X’) – f(X) 7 If △f < 0 then X <- X’ 8 else X<- X’ with probability exp(-△f/T) 9 T <- g(T) 10 If f(X) ! = 0 then T = T1 goto loop; 11 Return X |
优, 则重新随机初始化变元的初值,再开始模拟退火过程。
三、 实验结果
数据集 | 变量个数 | 字句个数 | 运行时间(ms) |
L= 50;T =50; T_min = 1; r = 0.5; | |||
1.txt | 30 | 129 | 242 |
2.txt | 30 | 129 | 1948 |
3.txt | 30 | 129 | 5185 |
4.txt | 40 | 172 | 12134 |
5.txt | 40 | 172 | 388 |
6.txt | 40 | 172 | 23304 |
7.txt | 50 | 215 | 810 |
8.txt | 50 | 215 | 73692 |
四、总结
在使用模拟退火算法求解Sat问题时算法需要注意的地方:
1)温度的设定及其变化函数;
2)在每个温度值下,进行尝试的次数;
3)评估函数选取问题。
但是本实验根据这三点修改跑出来的实验结果都没有达到文献[1]的效果。
参考
[1] 张德富, 黄文奇, 汪厚祥. 求解 SAT 问题的拟人退火算法[J].计算机学报, 2002, 25(2): 148-152.
模拟退火博客参考:
http://www.cnblogs.com/growing/archive/2010/12/16/1908255.html
http://www.bkjia.com/ASPjc/1015625.html
// 3SAT.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include"stdlib.h"
#include <algorithm>
#include <vector>
#include<math.h>
#include<time.h>
#include <iostream>
#include <fstream>
#include<ctime>
using namespace std;
#define SOURCE 1 //0:LAS VEGAS 1:拟人退火 2:拟人退火 3:模拟退火
#if SOURCE == 0
#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 )
{
for (int i = 1; i <= m; i++)
xValue[i] = 0;
for (int i = 0; i < n; i++)
input_delete[i] = false;
}
void checkAndDelete(void)
{
for (int j = 0; j < n; j++)//calulate whole sentence
{
int count_tt1 = 0;
int count_tt2 = 0;
for (int i = 0; i < l; i++)//caculate every sentence
{
int index = RETURN_POSITIVE_VALUE(input[j][i]);
if (((xValue[index] == TRUE) && (input[j][i] < 0)) || \
((xValue[index] == FALSE) && (input[j][i] > 0)))
count_tt1++;
if (((xValue[index] == TRUE) && (input[j][i] > 0)) || \
((xValue[index] == FALSE) && (input[j][i] < 0)))
count_tt2++;
}
if ((count_tt1 == 2) && (count_tt2 == 0))
{
for (int i = 0; i < l; i++)//caculate every sentence
{
int index = RETURN_POSITIVE_VALUE(input[j][i]);
if (xValue[index] == 0)
{
if (input[j][i] > 0)
xValue[index] = TRUE;
else
xValue[index] = FALSE;
}
}
input_delete[j] = true;
}
else if (count_tt2 > 0)
input_delete[j] = true;
}
}
bool satisfy(void)//flag: 返回当前[k] =true 赋值时子句满足的个数;false同理;trick:是否用技巧
{
for (int j = 0; j < n; j++)//calulate whole sentence
{
if (input_delete[j] == false)
{
int count_tt = 0;
for (int i = 0; i < l; i++)//caculate every sentence
{
int index = RETURN_POSITIVE_VALUE(input[j][i]);
if (((xValue[index] == TRUE) && (input[j][i] < 0)) || \
((xValue[index] == FALSE) && (input[j][i] > 0)))
count_tt++;
}
if (count_tt == 3)
return false;
}
}
return true;
}
int CaluteTrueNum(void)
{
if (satisfy())
{ int count_tt = 0;
for (int j = 0; j < n; j++)//calulate whole sentence
{
//if (input_delete[j] == false)
{
for (int i = 0; i < l; i++)//caculate every sentence
{
int index = RETURN_POSITIVE_VALUE(input[j][i]);
if (((xValue[index] == TRUE) && (input[j][i] > 0)) || \
((xValue[index] == FALSE) && (input[j][i] < 0)))
{
count_tt++;
break;
}
}
}
}
return count_tt;
}
return -1;
}
int CaluteTrueNum1(void)
{
int count_tt = 0;
for (int j = 0; j < n; j++)//calulate whole sentence
{
{
for (int i = 0; i < l; i++)//caculate every sentence
{
int index = RETURN_POSITIVE_VALUE(input[j][i]);
if (((xValue[index] == TRUE) && (input[j][i] > 0)) || \
((xValue[index] == FALSE) && (input[j][i] < 0)))
{
count_tt++;
break;
}
}
}
}
return count_tt;
}
int GetrandTF(void)
{
long i = rand() * (trueNum + falseNum) / RAND_MAX;
int retValue = TRUE;
if (i <= trueNum)
retValue = TRUE;
else
retValue = FALSE;
PRINTF_DEBUG("random = %d trueNum = %d falseNum = %d (trueNum + falseNum) = %d\n", i, trueNum, falseNum, (trueNum + falseNum));
return retValue;
}
void Backtrack(int k)
{
if (k > m)
{
;;// return true;
}
else
{
xValue[k] = FALSE;
if (satisfy())
Backtrack(k + 1);
xValue[k] = TRUE;
if (satisfy())
Backtrack(k + 1);
}
}
bool LV(void)
{
SetXvalueZero();
for (int k = 1; k < stopLV; k++)
{
PRINTF_DEBUG("########## k = %d\n", k);
if (xValue[k] == 0)
{
xValue[k] = FALSE;
falseNum = CaluteTrueNum();
xValue[k] = TRUE;
trueNum = CaluteTrueNum();
if ((falseNum < 0) && (trueNum < 0))
return false;
else if(falseNum < 0)
xValue[k] = TRUE;
else if (trueNum < 0)
xValue[k] = FALSE;
else
xValue[k] = GetrandTF();
checkAndDelete();
PRINTF_DEBUG("xValue[%d] = %d\n", k, xValue[k]);
}
}
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
srand((unsigned)time(NULL));
ofstream fout("output.txt");
for (int fileNum = 1; fileNum <= 1; fileNum++)
{
char str[10];
sprintf(str, "3SAT\\%d.txt", fileNum);
freopen(str, "r", stdin);
int i = 0;
while (scanf("%d%d%d%d", &(input[i][0]), &(input[i][1]), &(input[i][2]), &(input[i][3])) != EOF)
{
m = max(max(max(max(abs(input[i][0]), abs(input[i][1])), abs(input[i][2])), abs(input[i][3])), m);
i++;
}
n = i;
stopLV = m + 1;
#ifdef USE_BACKTRACK
stopLV = m - 10;
#else
stopLV = m + 1;
#endif
clock_t now_time = clock(); //long t1 = time(NULL);
while (LV() == false);
Backtrack(stopLV);
clock_t finish = clock();
long t = finish - now_time; //前后之差即程序运行时间 (ms)
PRINTF_DEBUG("variable_num = %d\nsentence_num = %d\nstopLV = %d\n", m, n, stopLV);
PRINTF_DEBUG("satisfy sentence num = %d\n", CaluteTrueNum1());
PRINTF_DEBUG("consume time = %d\n", t);
PRINTF_DEBUG("variable_num = %d\nsentence_num = %d\nstopLV = %d\n", m, n, stopLV);
fout << str << " " << m << " " << n << " " << t<< endl; // fout用法和cout一致, 不过是写到文件里面去
}
return 0;
}
#elif SOURCE == 1
int Caculate(vector<vector<int> > vec, vector<int > xValue)
{
int retValue = 0;
for (int i = 0; i < vec.size(); i++)
{
int clause = 1;//子句内部相乘;
for (int j = 0; j < vec[i].size(); j++)
{
int temp;
//cout << abs(vec[i][j]) << endl;
if (vec[i][j]>0)
temp = 1 - xValue[abs(vec[i][j])];
else
temp = xValue[abs(vec[i][j])];
clause = clause * temp;
}
retValue = retValue + clause;
}
return retValue;
}
int Caculate1(vector<vector<int> > vec, vector<int > xValue)
{
int retValue = 0;
for (int i = 0; i < vec.size(); i++)
{
for (int j = 0; j < vec[i].size(); j++)
{
//cout << abs(vec[i][j]) << endl;
if (((vec[i][j] > 0) && (xValue[abs(vec[i][j])] > 0)) ||
((vec[i][j] < 0) && (xValue[abs(vec[i][j])] < 1)) )
{
retValue++; break;
}
}
}
return retValue;
}
bool CaculateBool(vector<vector<int> > vec, vector<int > xValue)
{
int retValue = 0;
for (int i = 0; i < vec.size(); i++)
{
for (int j = 0; j < vec[i].size(); j++)
{
//cout << abs(vec[i][j]) << endl;
if (((vec[i][j] > 0) && (xValue[abs(vec[i][j])] > 0)) ||
((vec[i][j] < 0) && (xValue[abs(vec[i][j])] < 1)))
{
retValue++; break;
}
}
}
return (retValue == vec.size());
}
vector<int > GenerateX(vector<vector<int> > vec, vector<int > xValue)
{
vector<int > retValue(xValue);
vector<bool> flag(xValue.size(),false);
for (int i = 0; i < vec.size(); i++)
{
int clause = 1;//子句内部相乘;
for (int j = 0; j < vec[i].size(); j++)
{
int temp;
//cout << abs(vec[i][j]) << endl;
if (vec[i][j]>0)
temp = 1 - retValue[abs(vec[i][j])];
else
temp = retValue[abs(vec[i][j])];
clause = clause * temp;
}
if (clause != 0)
{
vector<int > temp;
if (flag[abs(vec[i][0])] == false) temp.push_back(vec[i][0]);
if (flag[abs(vec[i][1])] == false) temp.push_back(vec[i][1]);
if (flag[abs(vec[i][2])] == false) temp.push_back(vec[i][2]);
if (!temp.empty())
{
int index = rand() % temp.size();
index = abs(temp[index]);
retValue[index] = 1 - retValue[index];
flag[index] = true;
}
}
}
return retValue;
}
vector<int > GenerateX1(vector<vector<int> > vec, vector<int > xValue)
{
vector<int > retValue(xValue);
vector<bool> flag(xValue.size(), false);
vector<int > unsatisfied;
for (int i = 0; i < vec.size(); i++)
{
int clause = 1;//子句内部相乘;
for (int j = 0; j < vec[i].size(); j++)
{
int temp;
//cout << abs(vec[i][j]) << endl;
if (vec[i][j]>0)
temp = 1 - retValue[abs(vec[i][j])];
else
temp = retValue[abs(vec[i][j])];
clause = clause * temp;
}
if (clause != 0)
{
unsatisfied.push_back(i);
}
}
for (int i = 0; i < unsatisfied.size(); i++)
{
int temp;
int randow = rand() % (unsatisfied.size() - i) + i;
temp = unsatisfied[i];
unsatisfied[i] = unsatisfied[randow];
unsatisfied[randow] = temp;
}
for (int i = 0; i < unsatisfied.size(); i++)
{
vector<int > temp;
if (flag[abs(vec[unsatisfied[i]][0])] == false) temp.push_back(vec[unsatisfied[i]][0]);
if (flag[abs(vec[unsatisfied[i]][1])] == false) temp.push_back(vec[unsatisfied[i]][1]);
if (flag[abs(vec[unsatisfied[i]][2])] == false) temp.push_back(vec[unsatisfied[i]][2]);
if (!temp.empty())
{
int index = rand() % temp.size();
index = abs(temp[index]);
retValue[index] = 1 - retValue[index];
flag[index] = true;
}
}
return retValue;
}
vector<int > GenerateX2(vector<vector<int> > vec, vector<int > xValue)
{
vector<int > retValue(xValue);
vector<bool> flag(xValue.size(), false);
vector<int > unsatisfied;
for (int i = 0; i < vec.size(); i++)
{
int clause = 1;//子句内部相乘;
for (int j = 0; j < vec[i].size(); j++)
{
int temp;
//cout << abs(vec[i][j]) << endl;
if (vec[i][j]>0)
temp = 1 - retValue[abs(vec[i][j])];
else
temp = retValue[abs(vec[i][j])];
clause = clause * temp;
}
if (clause != 0)
{
unsatisfied.push_back(i);
}
}
int row = rand() % unsatisfied.size();
int column = rand() %3;
int index = abs(vec[row][column]);
retValue[index] = 1 - retValue[index];
return retValue;
}
void Johnson(vector<int > &ans)
{
for (int i = 0; i<ans.size(); i++)
{
if ((double)rand() / (RAND_MAX)>0.5)
{
ans[i] = 1;
}
else
{
ans[i] = 0;
}
}
}
#define TYPE 1
int _tmain(int argc, _TCHAR* argv[])
{
srand((unsigned)time(NULL));
ofstream fout("output1.txt", ios::app);//
ofstream debug("debug.txt");//
for (int fileNum = 1; fileNum <= 12; fileNum++)
{
char str[10];
sprintf(str, "3SAT\\%d.txt", fileNum);
freopen(str, "r", stdin);
vector<vector<int> > vec;
int a, b, c,d;
int maxX = 0;
while (scanf("%d%d%d%d", &(a), &(b), &(c), &(d)) != EOF)
{
vector<int > temp;
temp.push_back(a);
temp.push_back(b);
temp.push_back(c);
vec.push_back(temp);
//vec[i][3] = d;
maxX = max(max(max(abs(a), abs(b)), abs(c)), maxX);
}
vector<int > xValue(maxX+1, 0);
/*
* J(y):在状态y时的评价函数值
* Y(i):表示当前状态
* Y(i+1):表示新的状态
* r: 用于控制降温的快慢
* T: 系统的温度,系统初始应该要处于一个高温的状态
* T_min :温度的下限,若温度T达到T_min,则停止搜索
*/
bool runFlag = true; int tt = 0;
//double T, T0 = vec.size(), T_min = 0.1;
//double r = 0.5; int L = 10;
double T = 100, T_min = 1;
double r = 0.5; int L = 50, T0 = 100;
clock_t now_time = clock(); //long t1 = time(NULL);
loop:T = T0; tt = 0; Johnson(xValue);
while ((T > T_min) && runFlag)
{
for (int i = 0; i < maxX*L; i++)
{
#if TYPE == 1
vector<int > newX = GenerateX(vec, xValue);
int y1 = Caculate(vec, xValue);
if (y1 == 0) { runFlag = false; break; }
int y2 = Caculate(vec, newX);
if (y2 == 0) { xValue = newX; runFlag = false; break; }
int dE = (y2 - y1);
debug << " ++++ newX: " << y2 << " ---- y1: " << y1 << endl;
if (dE < 0) //表达移动后得到更优解,则总是接受移动
{
//cout << "dE < 0 xValue = newX;" << endl;
xValue = newX; //接受从Y(i)到Y(i+1)的移动
}
else if (dE == 0)
{
double i = rand()*1.0 / RAND_MAX;
//cout << exp(-(1.001 - T / T0) * 6) << endl;
//if (exp(-(1.001 - T / T0) * 6) > i)
{
//cout << "dE > 0 xValue = newX;" << endl;
//xValue = newX; //接受从Y(i)到Y(i+1)的移动
}
}
else
{
// 函数exp( dE/T )的取值范围是(0,1) ,dE/T越大,则exp( dE/T )也
double i = rand()*1.0 / RAND_MAX;
debug << " ++++ deta: " << dE << " ---- T: " << T << " ---- exp : " << exp(-dE / T) << endl;
if (exp(-dE / T) > i)
{
//cout << "dE > 0 xValue = newX;" << endl;
xValue = newX; //接受从Y(i)到Y(i+1)的移动
}
}
}
tt++;
cout << T << endl;
//T = T0 / (log(1 + tt) / log(2)); //降温退火 ,0<r<1 。r越大,降温越慢;r越小,降温越快,若r过大,则搜索到全局最优解的可能会较高,但搜索的过程也就较长。若r过小,则搜索的过程会很快,但最终可能会达到一个局部最优值
T = T0 / (1 + 1.5*tt);
// T = T * r;
#elif TYPE == 2
vector<int > newX = GenerateX(vec, xValue);
int y1 = Caculate1(vec, xValue);
if (y1 == vec.size()) { runFlag = false; break; }
int y2 = Caculate1(vec, newX);
if (y2 == vec.size()) { xValue = newX; runFlag = false; break; }
int dE = (y2 - y1);
debug << " ++++ newX: " << y2 << " ---- y1: " << y1 << endl;
if (dE > 0) //表达移动后得到更优解,则总是接受移动
{
//cout << "dE < 0 xValue = newX;" << endl;
xValue = newX; //接受从Y(i)到Y(i+1)的移动
}
else if (dE == 0)
{
double i = rand()*1.0 / RAND_MAX;
//cout << exp(-(1.001 - T / T0) * 6) << endl;
//if (exp(-(1.001 - T / T0) * 6) > i)
{
//cout << "dE > 0 xValue = newX;" << endl;
//xValue = newX; //接受从Y(i)到Y(i+1)的移动
}
}
else
{
// 函数exp( dE/T )的取值范围是(0,1) ,dE/T越大,则exp( dE/T )也
double i = rand()*1.0 / RAND_MAX;
debug << " ++++ deta: " << dE << " ---- T: " << T << " ---- exp : " << exp(dE / T) << endl;
if (exp(dE / T) > i)
{
//cout << "dE > 0 xValue = newX;" << endl;
xValue = newX; //接受从Y(i)到Y(i+1)的移动
}
}
}
tt++;
cout << " ---- T: " << T << " ---- exp : " << exp(-5 / T) << endl;
T = T0 / (log(1 + tt) / log(2)); //降温退火 ,0<r<1 。r越大,降温越慢;r越小,降温越快,若r过大,则搜索到全局最优解的可能会较高,但搜索的过程也就较长。若r过小,则搜索的过程会很快,但最终可能会达到一个局部最优值
//T = T0 / (1 + tt);
T = T * r;
#endif
}
if(CaculateBool(vec, xValue) == false)
{
//cout << "<><><><>"<<endl;
T0 = vec.size(); goto loop;
//T = 10; goto loop;
}
clock_t finish = clock();
long t = finish - now_time; //前后之差即程序运行时间 (ms)
#if TYPE == 1
cout << str << " Caculate " << maxX << " " << vec.size() << " " << L << " " << r << " " << t << endl; // fout用法和cout一致;
fout << str << " Caculate " << maxX << " " << vec.size() << " " << L << " " << r << " " << t << endl; // fout用法和cout一致;
#elif TYPE == 2
cout << str << " Caculate1 GenerateX" << maxX << " " << vec.size() << " " << L << " " << r << " " << t << endl; // fout用法和cout一致;
fout << str << " Caculate1 GenerateX" << maxX << " " << vec.size() << " " << L << " " << r << " " << t << endl; // fout用法和cout一致;
#endif
vec.clear();
}
return 0;
}
#elif SOURCE == 2
int Caculate(vector<vector<int> > vec, vector<int > xValue)
{
int count = 0;
for (int i = 0; i < vec.size(); i++)
{
int clause = 1;//子句内部相乘;
for (int j = 0; j < vec[i].size(); j++)
{
if (vec[i][j]<0)
{
int temp = (-1)*vec[i][j];
if (xValue[temp] == 0)
{
count++;
break;
}
}
else if (vec[i][j]>0)
{
if (xValue[vec[i][j]] == 1)
{
count++;
break;
}
}
}
}
return count;
}
bool CaculateBool(vector<vector<int> > vec, vector<int > xValue)
{
int retValue = 0;
for (int i = 0; i < vec.size(); i++)
{
for (int j = 0; j < vec[i].size(); j++)
{
int temp;
//cout << abs(vec[i][j]) << endl;
if (((vec[i][j] > 0) && (xValue[abs(vec[i][j])] > 0)) ||
((vec[i][j] < 0) && (xValue[abs(vec[i][j])] < 1)))
{
retValue++; break;
}
}
}
return (retValue == vec.size());
}
vector<int > GenerateX(vector<vector<int> > vec, vector<int > xValue)
{
vector<int > retValue(xValue);
int i = rand() % (xValue.size() - 1);
retValue[i + 1] = 1 - retValue[i + 1];
return retValue;
}
void Johnson(vector<int > &ans)
{
for (int i = 0; i<ans.size(); i++)
{
if ((double)rand() / (RAND_MAX)>0.5)
{
ans[i] = 1;
}
else
{
ans[i] = 0;
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
srand((unsigned)time(NULL));
ofstream fout("output.txt", ios::app);
for (int fileNum = 1; fileNum <= 12; fileNum++)
{
char str[10];
sprintf(str, "%d.txt", fileNum);
freopen(str, "r", stdin);
vector<vector<int> > vec;
int i = 0;
int a, b, c, d;
int maxX = 0;
while (scanf("%d%d%d%d", &(a), &(b), &(c), &(d)) != EOF)
{
vector<int > temp;
temp.push_back(a);
temp.push_back(b);
temp.push_back(c);
vec.push_back(temp);
//vec[i][3] = d;
maxX = max(max(max(abs(a), abs(b)), abs(c)), maxX);
i++;
}
vector<int > xValue(maxX + 1, 0);
/*
* J(y):在状态y时的评价函数值
* Y(i):表示当前状态
* Y(i+1):表示新的状态
* r: 用于控制降温的快慢
* T: 系统的温度,系统初始应该要处于一个高温的状态
* T_min :温度的下限,若温度T达到T_min,则停止搜索
*/
int T = 1000, T_min = 0.001;
double r = 0.98;
Johnson(xValue);
clock_t now_time = clock(); //long t1 = time(NULL);
while (T > T_min)
{
vector<int > newX = GenerateX(vec, xValue);
int y1 = Caculate(vec, xValue);
if (y1 == 0) break;
int y2 = Caculate(vec, newX);
if (y2 == 0) { xValue = newX; break; }
int dE = y2 - y1;
if (dE >= 0) //表达移动后得到更优解,则总是接受移动
xValue = newX; //接受从Y(i)到Y(i+1)的移动
else
{
// 函数exp( dE/T )的取值范围是(0,1) ,dE/T越大,则exp( dE/T )也
double i = rand()*1.0 / RAND_MAX;
if (exp(dE / T) > i)
xValue = newX; //接受从Y(i)到Y(i+1)的移动
}
T = r * T; //降温退火 ,0<r<1 。r越大,降温越慢;r越小,降温越快,若r过大,则搜索到全局最优解的可能会较高,但搜索的过程也就较长。若r过小,则搜索的过程会很快,但最终可能会达到一个局部最优值
//i++;
}
clock_t finish = clock();
long t = finish - now_time; //前后之差即程序运行时间 (ms)
cout << str << CaculateBool(vec, xValue) << endl;
fout << str << " " << maxX << " " << vec.size() << " " << t << endl; // fout用法和cout一致;
vec.clear();
}
return 0;
}
#elif SOURCE == 3
#include "stdafx.h"
#include <iostream>
#include <time.h>
#include <fstream>
#include <math.h>
using namespace std;
#define ANSSIZE 100
int ans[ANSSIZE];
int new_ans[ANSSIZE];
vector<vector<int> > x;
int n = 40;
int m = 172;
int filename = 6;
char str[100];
int randomi(int a, int b)
{
int c = rand() % (b - a + 1) + a;
return c;
}
double randomf(double a, double b)
{
double c = (double)(rand() % ((int)b - (int)a)) + a + (double)(rand() / (RAND_MAX + 1.0));
return c;
}
void Johnson(int n)
{
for (int i = 0; i<n; i++)
{
if ((double)rand() / (RAND_MAX)>0.5)
{
ans[i] = 1;
}
else
{
ans[i] = 0;
}
}
}
int satisfied_ans(int m)
{
int count = 0;
int i, j;
for (i = 0; i<m; i++)
{
for (j = 0; j<3; j++)
{
if (x[i][j]<0)
{
int temp = (-1)*x[i][j];
if (ans[temp - 1] == 0)
{
count++;
break;
}
}
else if (x[i][j]>0)
{
if (ans[x[i][j] - 1] == 1)
{
count++;
break;
}
}
}
}
return count;
}
int satisfied_new_ans(int m)
{
int count = 0;
int i, j;
for (i = 0; i<m; i++)
{
for (j = 0; j<3; j++)
{
if (x[i][j]<0)
{
int temp = (-1)*x[i][j];
if (new_ans[temp - 1] == 0)
{
count++;
break;
}
}
else if (x[i][j]>0)
{
if (new_ans[x[i][j] - 1] == 1)
{
count++;
break;
}
}
}
}
return count;
}
void disturb(int n)
{
for (int j = 0; j<n; j++)
{
new_ans[j] = ans[j];
}
int i = rand() % n;
new_ans[i] = 1 - new_ans[i];
}
bool accept(int deta, float T, ofstream &fout)
{
fout << " ++++ deta: " << deta << " ---- T: " << T << " ---- exp : " << exp(deta / T) << endl;
if (deta>0)
{
return 1;
}
else if (((deta<0) && (exp(deta / T)>randomf(0, 1))))
{
return 1;
}
return 0;
}
void SA3Sat(int n, int m)
{
int i;
Johnson(n); //初始解
float T = 1000; //初始温度
int L = 100 * n;
float T_time = 0.001;
sprintf(str, "output_%d.txt", filename);
ofstream fout(str, ios::app);
while (T>T_time&&satisfied_ans(m) != m)
{
for (i = 0; i<L; i++)
{
disturb(n);
// for (i = 0 ; i<n ; i++)
// {
// cout<<ans[i]<<" ";
// }
int deta = satisfied_new_ans(m) - satisfied_ans(m);
if (accept(deta, T, fout))
{
for (int j = 0; j<n; j++)
{
ans[j] = new_ans[j];
}
}
}
T = 0.98*T;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
// int n,m,i,j;
// cin>>n>>m; //3SAT问题
// x = new int*[m];
// for (i = 0 ; i<m ; i++)
// {
// x[i] = new int[3];
// }
// for (i = 0 ; i<m ; i++) //子句
// {
// for (j = 0 ; j<3 ; j++)
// {
// cin>>x[i][j];
// }
// }
srand((unsigned)time(NULL));
double run_time = 0.0; //执行时间
time_t start, end;
start = clock();
ifstream fin;
for (filename = 1; filename <= 12; filename++)
{
char str[100];
sprintf(str, "3SAT\\%d.txt", filename);
freopen(str, "r", stdin);
int i = 0;
int a, b, c, d;
int maxX = 0;
while (scanf("%d%d%d%d", &(a), &(b), &(c), &(d)) != EOF)
{
vector<int > temp;
temp.push_back(a);
temp.push_back(b);
temp.push_back(c);
x.push_back(temp);
//vec[i][3] = d;
maxX = max(max(max(abs(a), abs(b)), abs(c)), maxX);
i++;
}
m = i;
n = maxX;
SA3Sat(n, m);
cout << "可满足的子句个数:" << satisfied_ans(m) << endl;
cout << "变元的最终取值为:";
for (i = 0; i<n; i++)
{
cout << ans[i] << " ";
}
// if (satisfied_ans(m)==m)
// {
// cout<<"Yes";
// }
// else
// {
// cout<<"No";
// }
end = clock();
run_time = (end - start) / CLOCKS_PER_SEC;
printf("运行时间为 : %f\n", run_time);
}
system("pause");
return 0;
}
#endif