#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<time.h>
#include<set>
#include<queue>
#include<stack>
using namespace std;
const int MAXN=505;
//test
bool DEBUG1=false;
int testvar=50;
int TIME=0;
struct node{
set<int> F;
int fd;
};
bool find(set<int> C,int x){
//input:clause C and literal x
//output:1 denotes literal x is in C
// 0 denotes literal x is not in C
return C.find(x)!=C.end();//C.find(x)返回值: x在C中则返回x的位置,否则返回C.end
}
void copy(int *tTP,set<int> *C,int *TP,set<int> *tC,int n,int m,int &tn,int &tm){
//input:把TP的数据存到tTP里去
//output:no exist
tn=n,tm=m;
for (int i=1;i<MAXN;i++) tTP[i]=TP[i];
for (int i=1;i<MAXN;i++) tC[i]=C[i];
}
void back(int *tTP,set<int> *C,int *TP,set<int> *tC,int &n,int &m,int tn,int tm){
//input:把tTP的数据还原到TP里去
//output:no exist
n=tn,m=tm;
for (int i=1;i<MAXN;i++) TP[i]=tTP[i]; //注意
for (int i=1;i<MAXN;i++) C[i]=tC[i];
}
void find3clause(int &c1,int &c2,int &c3,int x,int m,set<int> *C){
//input:找到degree 为3的variable x的3个子句
//output:0
for (c1=1;c1<=m;c1++)
if (find(C[c1],x)) break;
for (c2=1;c2<=m;c2++)
if (find(C[c2],-x)) break;
for (c3=1;c3<=m;c3++)
if (c3!=c1 && c3!=c2 && (find(C[c3],x) || find(C[c3],-x))) break;
}
bool reFrash(int &m,int *X,int *TP,node *H,set<int> *C,int &Upbound){
//input: 子句数m X是存当前赋值, TP是每个X的当前状态, H是递推关系, C是当前所有的子句
//output:1 至少做了一次操作:{1.子句为空,去掉子句;2.如果一个子句的字符值为1,去掉该子句; 如果为0,删去该子句中的字符}
// 0 无操作
set<int>::iterator it;
for (int i=1;i<=m;i++){ //一个个clause看,是否为空,是否有值确定了
if (C[i].size()==0){
C[i]=C[m--];
Upbound--;
return true;
}
for (it=C[i].begin();it!=C[i].end();it++){
if (TP[abs(*it)]!=0) continue; //要值确定了才
if (X[abs(*it)]==1){
if (*it>0) C[i]=C[m--];
else C[i].erase(*it);
}else{
if (*it<0) C[i]=C[m--];
else C[i].erase(*it);
}
return true;
}
}
return false;
}
void initial(int &n,int &m,set<int> *C){ //读取数据
//input:读入数据
scanf("%d%d",&n,&m);
for (int t=1;t<=m;t++){
int x;
C[t].clear();
while (~scanf("%d",&x) && x){
C[t].insert(x);
}
}
}
bool rule1(int n,int &m,int *X,int *TP,node *H,set<int> *C){
set<int>::iterator it;
bool f=false;
for (int i=1;i<=m;i++)
for (it=C[i].begin();it!=C[i].end();it++){
if (!find(C[i],-*it)) continue; // ~x x 别和X[i]=0,1弄混
C[i--]=C[m--];
f=true;
break;
}
for (int x=1;x<=n;x++){
if (TP[x]!=-1) continue;
int p1=0,p2=0;
for (int i=1;i<=m;i++){
if (C[i].size()!=1) continue;
if (find(C[i],x)) p1=i;
if (find(C[i],-x)) p2=i;
}
if (!p1 || !p2) continue; //找不到包含~x的unit clause
if (p1>p2) //多个删除注意顺序
C[p1]=C[m--],C[p2]=C[m--]; //出问题
else
C[p2]=C[m--],C[p1]=C[m--];
f=true;
}
return f;
}
bool rule2(int n,int &m,int *X,int *TP,node *H,set<int> *C){ //不用管dgree
for (int z=1;z<=n;z++){
if (TP[z]!=-1) continue;
int p1=0,p2=0,h1=0,h2=0; //p1= x个数 p2= -x个数 h1= x unit h2= -x unit
for (int i=1;i<=m;i++){
if (find(C[i],z)) {
p1++;
if (C[i].size()==1) h1++;
}
if (find(C[i],-z)) {
p2++;
if (C[i].size()==1) h2++;
}
}
if (h1>=p2){
TP[z]=0; //z可以直接赋值
X[z]=1;
return true;
}
if (h2>=p1){
TP[z]=0; //z可以直接赋值
X[z]=0;
return true;
}
}
return false;
}
bool rule3(int n,int &m,int *X,int *TP,node *H,set<int> *C){
int degree[MAXN];
set<int>::iterator it;
memset(degree,0,sizeof(degree));
for (int i=1;i<=m;i++)
for (it=C[i].begin();it!=C[i].end();it++)
degree[abs(*it)]++;
for (int x=1;x<=n;x++){
if (TP[x]!=-1 || degree[x]!=2) continue;
int c1,c2;
for (int i=1;i<=m;i++){ // x,x ~x,~x在rule2会过滤掉
if (find(C[i],x)) c1=i;
if (find(C[i],-x)) c2=i;
}
C[c1].insert(C[c2].begin(),C[c2].end()); //合并set
C[c1].erase(x),C[c1].erase(-x);
TP[x]=1,H[x].F=C[c2],H[x].F.erase(-x);// x由c2得来
C[c2]=C[m--]; //删掉c2
return true;
}
return false;
}
bool rule5(int n,int &m,int *X,int *TP,node *H,set<int> *C){ //在实现的时候只需要让x=1
int degree[MAXN];
set<int>::iterator it;
memset(degree,0,sizeof(degree));
for (int i=1;i<=m;i++)
for (it=C[i].begin();it!=C[i].end();it++)
degree[abs(*it)]++;
for (int x=1;x<=n;x++){
if (TP[x]!=-1 || degree[x]!=3) continue;
int c1,c2,c3;
find3clause(c1,c2,c3,x,m,C); //找到这三个clause
int y=0;
for (it=C[c1].begin();it!=C[c1].end();it++){
if (degree[abs(*it)]!=3 || TP[abs(*it)]!=-1) continue; //是否出问题
if (*it==x) continue;
if (!find(C[c2],*it) && !find(C[c2],-*it)) continue;
if (!find(C[c3],*it) && !find(C[c3],-*it)) continue;
y=abs(*it);
break;
}
if (!y) continue;
if (find(C[c3],x)){ // x为(2,1)
TP[x]=0;
X[x]=1;
}else{ // x为(1,2)
TP[x]=0;
X[x]=0;
}
return true;
}
return false;
}
bool rule6(int n,int &m,int *TP,node *H,set<int> *C){ //注意m为变参
int degree[MAXN];
set<int>::iterator it;
memset(degree,0,sizeof(degree));
for (int i=1;i<=m;i++)
for (it=C[i].begin();it!=C[i].end();it++)
degree[abs(*it)]++;
for (int x=1;x<=n;x++){
if (TP[x]!=-1 || degree[x]!=3) continue;
int c1,c2,c3,y=0;
find3clause(c1,c2,c3,x,m,C); //找到这三个clause
for (it=C[c1].begin();it!=C[c1].end();it++){
if (*it==x) continue; //注意
if (TP[abs(*it)]!=-1) continue; //需要么
if (degree[abs(*it)]!=3) continue; //注意限制y的degree=3 *it的正负不用限制
if (find(C[c2],-*it)){
y=*it;
break;
}
if (find(C[c3],-x) && find(C[c3],-*it)){ //注意C3必须是包含-x的才可以
y=*it;
swap(c2,c3);
break;
}
}
if (!y) continue; //找不到对应的y
if (find(C[c3],x)){ //x为(2,1)
TP[x]=1; //x的值由c2推出
H[x].F=C[c2],H[x].F.erase(-x);
C[c2].insert(C[c3].begin(),C[c3].end());
C[c2].erase(x),C[c2].erase(-x);
if (c1>c3) //多个删除注意顺序
C[c1]=C[m--],C[c3]=C[m--]; //注意先改clause再删除clause
else
C[c3]=C[m--],C[c1]=C[m--];
}else{ //x为(1,2)
TP[x]=1; //x的值由c1推出
H[x].F=C[c1],H[x].F.erase(x);
C[c1].insert(C[c3].begin(),C[c3].end());
C[c1].erase(x),C[c1].erase(-x);
if (c2>c3) //多个删除注意顺序
C[c2]=C[m--],C[c3]=C[m--]; //注意先改clause再删除clause
else
C[c3]=C[m--],C[c2]=C[m--];
}
return true;
}
return false;
}
bool rule7(int n,int &m,int *X,int *TP,node *H,set<int> *C){
int degree[MAXN];
set<int>::iterator it;
memset(degree,0,sizeof(degree));
for (int i=1;i<=m;i++)
for (it=C[i].begin();it!=C[i].end();it++)
degree[abs(*it)]++;
for (int z2=1;z2<=n;z2++){
if (TP[z2]!=-1 || degree[z2]!=3) continue;
int c1,c2,c3;
find3clause(c1,c2,c3,z2,m,C); //找到这三个clause
//找到了degree=3的z2三个clause c1,c2,c3
int z1=0;
for (it=C[c1].begin();it!=C[c1].end();it++)
if (find(C[c2],*it) && TP[abs(*it)]==-1){ //是否需要限制TP[*it]
z1=*it;
break;
}
if (!z1) continue;
if (find(C[c3],z2)){ //z2为(2,1)
C[c1].erase(z1);
}else{ //z2为(1,2)
C[c2].erase(z1);
}
return true;
}
return false;
}
bool rule8(int &n,int &m,int *X,int *TP,node *H,set<int> *C){ // (~x',D1,D2)
int degree[MAXN];
set<int>::iterator it;
memset(degree,0,sizeof(degree));
for (int i=1;i<=m;i++)
for (it=C[i].begin();it!=C[i].end();it++)
degree[abs(*it)]++;
for (int x=1;x<=n;x++){
if (TP[x]!=-1 || degree[x]!=3) continue;
int c1,c2,d1,d2;
find3clause(c1,c2,d1,x,m,C);
if (find(C[d1],x)){ //x,y为(2,1)
swap(c2,d1);
int y=0;
for (it=C[c1].begin();it!=C[c1].end();it++){
if (*it<0 || TP[*it]!=-1 || degree[*it]!=3) continue;
if (*it==x) continue;
if (find(C[c2],*it)){
y=*it; //y满足: 正的在c1,c2中出现 y未赋值 y的degree=3 y!=x
break;
}
}
if (!y) continue; //找不到对应的y
int yc1,yc2;
find3clause(yc1,d2,yc2,y,m,C);
H[y].F.clear(),H[y].F.insert(-x);
H[x].F=C[d1],H[x].F.erase(-x);
TP[++n]=-1;
TP[x]=TP[y]=n;
H[x].fd=H[y].fd=0;//x,y的值将由n来决定
C[c1].erase(x),C[c1].erase(y),C[c1].insert(n);
C[c2].erase(x),C[c2].erase(y),C[c2].insert(n);
C[d1].insert(C[d2].begin(),C[d2].end());
C[d1].erase(-x),C[d1].erase(-y),C[d1].insert(-n);
C[d2]=C[m--]; //删去d2
}else{ //x,y为(1,2)
swap(c1,d1);
int y=0;
for (it=C[c1].begin();it!=C[c1].end();it++){
if (*it>0 || TP[-*it]!=-1 || degree[-*it]!=3) continue;
if (-*it==x) continue;
if (find(C[c2],*it)){
y=-*it;
break;
}
}
if (!y) continue; //找不到对应的y
int yc1,yc2;
find3clause(d2,yc2,yc1,y,m,C);
H[x].F.clear(),H[x].F.insert(-y);
H[y].F=C[d1],H[y].F.erase(x);
TP[++n]=-1;
TP[x]=TP[y]=n;
H[x].fd=H[y].fd=1;//x,y的值将由n来决定
C[c1].erase(-x),C[c1].erase(-y),C[c1].insert(n);
C[c2].erase(-x),C[c2].erase(-y),C[c2].insert(n);
C[d1].insert(C[d2].begin(),C[d2].end());
C[d1].erase(x),C[d1].erase(y),C[d1].insert(-n);
C[d2]=C[m--];
}
return true;
}
return false;
}
bool rule9(int &m,set<int> *C){
set<int>::iterator it;
for (int i=1;i<=m;i++){
if (C[i].size()!=2) continue;
int x[2],t=0;
for (it=C[i].begin();it!=C[i].end();it++) x[t++]=*it;
int p0=0,p1=0;
for (int j=1;j<=m;j++){
if (C[j].size()!=1) continue;
if (find(C[j],-x[0])) p0=j;
if (find(C[j],-x[1])) p1=j;
}
if (!p0 || !p1) continue;
C[p1].insert(-x[0]); //先插入 后删除
if (i>p0)
C[i]=C[m--],C[p0]=C[m--];
else
C[p0]=C[m--],C[i]=C[m--];
return true;
}
return false;
}
bool used[MAXN];
void searchH(int i,int n,int *TP,node *H,int *X){
//展开递推关系
//判断第i个变量的值, 通过H
//input:i is the existing extentable variableclause C and literal x
//output:1 denotes literal x is in C
// 0 denotes literal x is not in C
set<int>::iterator it;
if (TP[i]==0) return; //值是确定的
if (TP[i]>1){ //其值依赖于H[i].fx与H[i].F的值
searchH(TP[i],n,TP,H,X);
if (X[TP[i]]==0){ //根据rule8规则
TP[i]=0,X[i]=H[i].fd; //根据rule8规则
return;
}
}
int t=0; //只看H[i].F的值
for (it=H[i].F.begin();it!=H[i].F.end();it++){
int x=*it;
searchH(abs(x),n,TP,H,X);
if ((x>0 && X[x]==1) || (x<0 && X[-x]==0)){
t=1;
break;
}
}
TP[i]=0,X[i]=t;
}
void consH(int n,int *TP,node *H,int *tTP,int *X){
//根据H,把X的值全构造出来
//input:clause C and literal x
//output:1 denotes literal x is in C
// 0 denotes literal x is not in C
for (int i=1;i<=n;i++) tTP[i]=TP[i];
for (int i=1;i<=n;i++) searchH(i,n,TP,H,X);
}
void reTP(int n,int *TP,int *tTP){
//还原tp
for (int i=1;i<=n;i++) TP[i]=tTP[i];
}
void branch(int &n,int &m,int n0,int m0,int *X,int &maxNum,int *ans,set<int> *C,set<int> *C0,int *TP,node* H,int Upbound){
while (1){
while (reFrash(m,X,TP,H,C,Upbound)); //done
if (Upbound<=maxNum) return;
if (rule1(n,m,X,TP,H,C)) continue; //done
if (rule2(n,m,X,TP,H,C)) continue; //done
if (rule3(n,m,X,TP,H,C)) continue; //done
if (rule5(n,m,X,TP,H,C)) continue; //done
if (rule6(n,m,TP,H,C)) continue; //done
if (rule7(n,m,X,TP,H,C)) continue; //done
if (rule8(n,m,X,TP,H,C)) continue; //done
if (rule9(m,C)) continue; //done
break;
}
set<int> tC[MAXN];
int tn,tm,tTP[MAXN],degree[MAXN],k=0;
set<int>::iterator it;
memset(degree,0,sizeof(degree));
for (int i=1;i<=m;i++)
for (it=C[i].begin();it!=C[i].end();it++)
degree[abs(*it)]++;
for (int i=1;i<=n;i++)
if (TP[i]==-1 && degree[k]<degree[i]) k=i;
if (k){
copy(tTP,C,TP,tC,n,m,tn,tm); //保护现场
TP[k]=0; //值确定
X[k]=0;
branch(n,m,n0,m0,X,maxNum,ans,C,C0,TP,H,Upbound);
back(tTP,C,TP,tC,n,m,tn,tm); //还原现场
TP[k]=0; //----大错点----不加则死循环---
X[k]=1;
branch(n,m,n0,m0,X,maxNum,ans,C,C0,TP,H,Upbound);
back(tTP,C,TP,tC,n,m,tn,tm); //还原现场
return;
}
consH(n0,TP,H,tTP,X); //展开递推关系TP,H
int t=0;
for (int i=1;i<=m0;i++)
for (it=C0[i].begin();it!=C0[i].end();it++){
if ((*it>0 && X[*it]==1) || (*it<0 && X[-*it]==0)){
t++;
break;
}
}
if (t>maxNum){
maxNum=t;
for (int i=1;i<=n0;i++) ans[i]=X[i];
}
reTP(n0,TP,tTP);
return;
}
int main(int argc,char **arg){
freopen("sgen1-sat-60-100.cnf","r",stdin);
freopen("output.txt","w",stdout);
int n,m,n0,maxNum=0;
set<int> C[MAXN],C0[MAXN];
int ans[MAXN];
int TP[MAXN]; //TP存变量的状态是 -1 未知 0 为确定值 1 由H[i].F得到 2看H[i].fx之后得到
node H[MAXN];
initial(n,m,C0);
n0=n;
int X[MAXN]={0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,
1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0 };
memset(TP,-1,sizeof(TP));
for (int i=1;i<=m;i++) C[i]=C0[i];
if(DEBUG1)
{
//----------for test
memset(TP,0,sizeof(TP));
srand((int)time(0));
for (int i=1;i<=testvar;i++){
int h=rand()%60+1;
while (1) {
if (TP[h]==0) break;
h=rand()%60+1;
}
TP[h]=-1;
}
}
//----------for test
else memset(X,-1,sizeof(X));
branch(n,m,n,m,X,maxNum,ans,C,C0,TP,H,m);
printf("%d\n",maxNum);
for (int i=1;i<=n0;i++)
{
if(ans[i]) printf("%d ", i);
else printf("%d ",-i);
if(i%20==0) puts("");
}
puts("");
return 0;
}
SAT
最新推荐文章于 2023-02-27 12:44:31 发布