# include <iostream>
# include <fstream>
# include <string>
# include <ctime>
using namespace std;
#define SAT 3 //每个子句所含变量的个数,即定义N-SAT问题的N
int **arr; //描述SAT问题的二维数组
int Var_Num; //变元个数
int Clause_Num; //子句个数
ifstream fin;
ofstream fout;
void Random(int *v, int *s);
int Proper_Num(int *s);
void Reverse(int *v,int *s, int num);
void Local_Search(double &duration);
void Read_And_Save(int it);
int main()
{
srand(time(NULL));
fout.open("result50-Local_Search_Algorithm.txt");
fout << "#姓名学号" << endl;
double totaltime = 0.0;
for (int i = 1; i <= 10; ++i)
{
double duration=0.0;
Read_And_Save(i);
Local_Search(duration);
totaltime += duration;
}
fout.close();
cout<<"平均时间为: "<< totaltime / 10 <<" 秒 "<<endl;
system("pause");
return 0;
}
//随机生成一个真值指派v,并计算在这个真值指派v下每个子句中满足1的数量,可能值从0-3,存于s中
void Random(int *v, int *s)
{
int temp, i, j, k;
for (i = 0; i < Var_Num;i++)
v[i] = rand() % 2;
memset(s, 0, sizeof(int) * Clause_Num);
for (k = 0; k < Var_Num; k++)
for (i = 0; i < Clause_Num; i++)
for (j = 0; j < SAT; j++)
{
temp = (v[k] == 1) ? (k + 1) : -(k + 1);
if (arr[i][j] == temp)
{
++s[i];
break;
}
}
}
//计算符合的子句数,可能值从0-91
int Proper_Num(int *s)
{
int k = 0;
for (int i = 0; i < Clause_Num; i++)
if (s[i] > 0) ++k;
return k;
}
//尝试对第num位进行翻转
void Reverse(int *v,int *s, int num)
{
int i, j, temp;
int preSatify = Proper_Num(s);
int *offset = new int[Clause_Num];
memset(offset, 0, sizeof(int) * Clause_Num);
for (i = 0; i < Clause_Num; i++) //计算翻转后的可满足子句数量的偏移值for (j = 0;j < SAT;j++)
{
temp = (v[num] == 1) ? (num + 1) : -(num + 1);
if (arr[i][j] == temp)
{
offset[i] = offset[i] - 1;
break;
}
if (arr[i][j] == -temp)
{
offset[i] = offset[i] + 1;
break;
}
}
for (i = 0;i < Clause_Num; i++) //修改生成新的可满足子句
s[i] = s[i] + offset[i];
int newSatify = Proper_Num(s); //计算新的可满足子句个数
if (newSatify > preSatify) //满足子句个数增加则翻转
v[num] = 1 - v[num];
else
for (i = 0; i < Clause_Num; i++) //否则复原可满足子句向量
s[i] = s[i] - offset[i];
delete[] offset;
}
//局部搜索思想求解
void Local_Search(double &duration)
{
int i;
int *sentence = new int[Clause_Num];
int *value = new int[Var_Num];
int tries = 0; //尝试次数
int changenum; //翻转位
double start_time = (double)clock();
Random(value, sentence); //随机生成一组真值指派
while (Proper_Num(sentence) < Clause_Num) //当未使91个子句都满足时...
{
if (tries >= Var_Num * 10) //若尝试次数大于变元数的10倍
{
Random(value, sentence);
tries = 0;
}
changenum = rand() % Var_Num; //随机选一个翻转位
Reverse(value, sentence, changenum); //尝试翻转
++tries;
}
double end_time = (double)clock();
duration =(end_time-start_time)/1000;
fout << "-" << SAT << "-" << Var_Num << "-" << Clause_Num << "-" << duration << endl;
for (i = 0; i < Var_Num; ++i)
fout << value[i];
fout << endl;
for (i = 0; i < Clause_Num;i++)
delete[] arr[i];
delete[] sentence;
delete[] arr;
}
//读取文件并把问题各子句的描述存进二维数组arr
void Read_And_Save(int it)
{
string s;
int i, j, nn;
char sc[20];
fout << "#t" << it << ".txt ";
itoa(it, sc, 10);
string infn = "test\\t" + (string)sc;
infn += ".txt";
fin.open(infn.c_str());
do
fin >> s;
while(s != "cnf");
fin >> Var_Num;
fin >> Clause_Num;
arr = new int*[Clause_Num];
for (i = 0; i < Clause_Num; i++)
{
arr[i] = new int[SAT];
for (j = 0; j < SAT; j++)
fin >> arr[i][j];
fin >> nn;
}
fin.close();
}。