3-SAT

3-SATを解く、Schoeningのアルゴリズムという乱択アルゴリズムを実装した。
変数はアルファベット1文字のみ。否定は~。
未検証。

(a|~b|~c)&(b|c|~d)
のように入力を与える。文字同士の間に空白は入れない。

#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<cctype>
#include<map>
#include<set>
#include<ctime>

using namespace std;

string f;         //論理式
int n;            //変数の個数
int R;            //ラウンド数
int now;          //構文解析用
int pos;          //満たしていないclause の ( のid
int litnum;       //満たしていないclause の literal の数
map<char,bool>mp; //変数の割り当て

bool literal(void){
  now++;
  if(isalpha(f[now-1]))return mp[f[now-1]];
  if(isdigit(f[now-1]))return mp[f[now-1]];
  now++;
  return !mp[f[now-1]];
}

bool clause(void){
  bool res=literal();
  while(true){
    if(f[now]=='|'){
      now++;
      bool tmp=literal();
      res|=tmp;
    }
    else break;
  }
  return res;
}

bool expression(void){
  bool res=true;
  while(true){
    if(f[now]=='('){
      int tpos=now++;
      bool tmp=clause();
      if(!tmp){
        pos=tpos;
        litnum=(now-pos+1)/2;
      }
      res&=tmp;
      now++;
    }
    else if(f[now]=='&'){
      now++;
    }
    else break;
  }
  return res;
}

typedef unsigned int uint;

static uint x=123456789,y=362436069,z=521288629,w=88675123;

void init_xor128(uint s) {
  z^=s;
  z^=z>>21;
  z^=z<<27;
  z^=z>>4;
  z*=2685821657736338717LL;
}

uint xor128(void) {
  uint t=(x^(x<<11));
  x=y; y=z; z=w;
  return ( w=(w^(w>>19))^(t^(t>>8)) );
}

bool randomWalk3Sat(void){

  for(int r=0;r<R;r++){

    for(char c='A';c<='Z';c++)mp[c]=(bool)(xor128()%2);
    for(char c='a';c<='z';c++)mp[c]=(bool)(xor128()%2);

    for(int k=0;k<3*n;k++){
      now=0;
      if(expression())return true;
      int id=pos+(int)(xor128()%litnum)*2+1;
      if(!isdigit(f[id]))mp[f[id]]=!mp[f[id]];
    }
  }
  return false;
}

int main(void){

  while(cin >> f){
    set<char>S;
    for(int i=0;i<f.size();i++)
      if(isalpha(f[i]) || isdigit(f[i]))S.insert(f[i]);

    R=1000;
    n=S.size();
    time_t timer;
    time(&timer);
    init_xor128((uint)timer);

    mp['0']=false;
    mp['1']=true;

    cout << randomWalk3Sat() << endl;
  }

  return 0;
}