Kakuro - Cross Sums

问题如下 一个简单的例子

使用GAC加速 解决CSP问题  Kakuro - Cross Sums-LMLPHP

可以看出限制条件是某行或某列的某几个空白格子求和等于某个值,且每一个限制中的格子所填的数必须为1-9且互异。

直接暴力搜索,空白格子太多,复杂度是无法接受的。

我们考虑用GAC加速。

所谓GAC就是在填充一个变量的时候,保证和这个变量相关的所有限制的所有变量都是一致的!

什么是一致呢? 就是对一个变量的论域内的所有可取的值,其他相关变量可以有一种取值满足限制条件。

如果我们在搜索的全过程都能满足GAC的一致性,那么每一步所选的变量,最后就可以是一个有效的解。

下面来解释一下具体的GAC搜索过程

初始状态,所有的变量论域都是满的,我们的目的是找到一个解,也就是说目标状态是这样的:

所有变量的论域中有且只有一个可选变量,同时满足GAC。根据GAC的定义,这显然就是CSP问题的解了。

如何从初始状态达到目标状态呢? 显然就是删除变量论域中的可取值了(也就是对变量赋值)

每次选择一个变量,把目标值以外的其他值全部从论域中删除,然后进行GAC ,达到一致状态,然后继续选取变量,继续GAC...

有一点要注意,搜索是有回溯的,所以所有删除的论域取值都要进行标记,以便restore。

下面给出伪代码

使用GAC加速 解决CSP问题  Kakuro - Cross Sums-LMLPHP

对于15*15的数据,我的cpp代码运行效果如下

使用GAC加速 解决CSP问题  Kakuro - Cross Sums-LMLPHP

下面给出cpp代码 和6个测试数据

// Wang Bingsen 15336169

#include<bits/stdc++.h>

using namespace std;
struct Variable
{
bool Domain[10];
int Row,Col,dsize;
int Value;
Variable()
{
this->Value=0;
this->dsize=9;
memset(Domain,true,sizeof(Domain));
Row=Col=-1;
}
};
struct Constrain
{
bool Used[10];
int Goal;
vector<int>Scop;
Constrain()
{
memset(Used,false,sizeof(Used));
Goal=-1;
Scop.resize(0);
}
Constrain(int c)
{
Scop.resize(0);
memset(Used,false,sizeof(Used));
Goal=0;
this->Goal=c;
}
}; inline char getc();
void Init();
bool Support(int seted,Constrain & C);
bool GAC_Enforce(queue<int> & P,vector<pair<int,int> > & Restore);
void Reimburse(vector<pair<int,int> >& Re);
bool Set();
bool Solve(); vector<Variable> Var;
vector<Constrain> Con;
int n,m;
typedef pair<int,int> Problem;
Problem Prob[20][20];
inline char getc()
{
char c;
while(true)
{
scanf("%c",&c);
if(c!=' '&&c!='\n') return c;
}
return c;
} void Init()
{
Var.clear(); Var.resize(0);
Con.clear(); Con.resize(0);
scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)
{ for(int j=1;j<=m;j++)
{
char ch=getc();
if(ch=='*')
{
Prob[i][j]=make_pair(-1,-1);
continue;
}
if(ch=='0')
{
Variable nV;
Prob[i][j]=make_pair(-3,(int)Var.size());
Var.push_back(nV);
continue;
}
if(ch=='(')
{
int a=0,b=0;
scanf("%d%c%d%c",&a,&ch,&b,&ch);
int c=-2,d=-2;
if(a!=0)
{
Constrain nC(a);
c=(int)Con.size();
Con.push_back(nC);
}
if(b!=0)
{
Constrain nC(b);
d=(int)Con.size();
Con.push_back(nC);
}
Prob[i][j]=make_pair(c,d);
continue;
}
}
} for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(Prob[i][j].first==-1||Prob[i][j].first==-3) continue; int a=Prob[i][j].first,b=Prob[i][j].second;
if(a!=-2)
{
int ii=i+1;
vector<int> vec;
while(ii<=n&&Prob[ii][j].first==-3)
{
vec.push_back(Prob[ii][j].second);
ii++;
} for(int k=0;k<vec.size();k++)
{
Var[vec[k]].Col=a;
Con[a].Scop.push_back(vec[k]);
}
}
if(b!=-2)
{
int jj=j+1;
vector<int> vec;
while(jj<=m&&Prob[i][jj].first==-3)
{
vec.push_back(Prob[i][jj].second);
jj++;
} for(int k=0;k<vec.size();k++)
{
Var[vec[k]].Row=b;
Con[b].Scop.push_back(vec[k]);
}
}
}
} } bool Support(int seted,Constrain & C)
{
if(C.Goal<=0)return false;
bool ret=false;
int loc=-1,min=11;
for(int i=0;i<C.Scop.size()&&min>2;i++)
{
int nv=C.Scop[i];
if(Var[nv].Value!=0)continue;
if(loc==-1||Var[nv].dsize<min){loc=nv;min=Var[nv].dsize;break;}
}
if(loc==-1)return false;
if(seted==(int)C.Scop.size())
{
if(C.Goal<=9&&(!C.Used[C.Goal])&&Var[loc].Domain[C.Goal])return true;
else return false;
} for(int v=9;v>=1&&!ret;v--)
{
if(!Var[loc].Domain[v]||v>=C.Goal||C.Used[v])continue;
Var[loc].Value=v;
C.Goal-=v;
C.Used[v]=true;
ret=Support(seted+1,C); Var[loc].Value=0;
C.Goal+=v;
C.Used[v]=false;
}
return ret;
} bool cmp(int a,int b)
{
return Var[a].dsize<Var[b].dsize;
}
bool GAC_Enforce(queue<int> & P,vector<pair<int,int> > & Restore)
/*
This implementation has refered the pseudo_code for GAC in the Course Slide week8.pdf.
Other than that, there should be no such thing like plagiarize.
╮(╯_╰)╭
*/ {
bool inq[1000];
memset(inq,false,sizeof(inq));
queue<int> Q;
while(!P.empty())
{
int Fr=P.front();P.pop();
inq[Fr]=true;
Q.push(Fr);
} while(!Q.empty())
{
int Fr=Q.front();Q.pop();
inq[Fr]=false;
sort(&Con[Fr].Scop[0],&Con[Fr].Scop[0]+(int)Con[Fr].Scop.size(),cmp);//MRV
for(int i=0;i<Con[Fr].Scop.size();i++)
{
int nv=Con[Fr].Scop[i];
if(Var[nv].dsize<=0)return false;
for(int v=9;v>=1;v--)
{
if(!Var[nv].Domain[v]||Con[Fr].Used[v])continue;
Var[nv].Value=v;
Con[Fr].Goal-=v;
Con[Fr].Used[v]=true;
if(!Support(2,Con[Fr]))
{
Var[nv].Domain[v]=false;
Var[nv].dsize--;
Restore.push_back(make_pair(nv,v));
if(Var[nv].dsize==0)
{
while(!Q.empty())Q.pop();
Var[nv].Value=0;
Con[Fr].Goal+=v;
Con[Fr].Used[v]=false;
return false;
}
else
{
int a=Var[nv].Col,b=Var[nv].Row;
if(a!=-1&&(!inq[a])){inq[a]=true;Q.push(a);}
if(b!=-1&&(!inq[b])){inq[b]=true;Q.push(b);}
}
} Var[nv].Value=0;
Con[Fr].Goal+=v;
Con[Fr].Used[v]=false;
}
}
}
return true;
} void Reimburse(vector<pair<int,int> >& Re)
{
for(int i=0;i<Re.size();i++)
{
Var[Re[i].first].Domain[Re[i].second]=true;
Var[Re[i].first].dsize++;
}
return ;
}
bool Set()
{
bool ret=false;
int loc=-1,min=11;
for(int i=0;i<Var.size()&&min>2;i++)
{
if(Var[i].dsize==1)continue;
if(Var[i].dsize==0)return false;
if(loc==-1||Var[i].dsize<min){loc=i;min=Var[i].dsize;}
}
if(loc==-1)return true; for(int v=9;v>=1&&!ret;v--)
{
if(!Var[loc].Domain[v])continue;
vector<pair<int,int> > Re;Re.resize(0);
for(int vv=9;vv>=1;vv--)
{
if(vv==v||(!Var[loc].Domain[vv]))continue;
Var[loc].Domain[vv]=false;
Var[loc].dsize--;
Re.push_back(make_pair(loc,vv)); }
queue<int> Q; while(!Q.empty())Q.pop();
int a=Var[loc].Col,b=Var[loc].Row;
if(a!=-1)Q.push(a);if(b!=-1)Q.push(b);
if(GAC_Enforce(Q,Re))
{
ret=Set();
if(ret)return true;
}
Reimburse(Re);
}
return ret;
} bool Solve()
{
/*queue<int>Q;
for(int i=0;i<Con.size();i++)
Q.push(i);
vector<pair<int,int> > V;
GAC_Enforce(Q,V);
initiate GAC not necessary*/
if(!Set())return false;
for(int i=0;i<Var.size();i++)
{
for(int v=9;v>=1;v--)
{
if(Var[i].Domain[v]){Var[i].Value=v;break;}
}
}
return true;
} void spa(int x)
{
for(int i=0;i<x;i++)
printf(" ");
}
void Print(bool flg)
{
if(!flg)printf("%dX%d\nInput:\n",n,m);
else printf("\n\nSolution:\n");
int ns=6;
for(int i=1;i<=n;i++)
{
ns=6;
for(int j=1;j<=m;j++)
{
if(Prob[i][j].first==-3)
{
spa(ns);printf("%d",Var[Prob[i][j].second].Value);
ns=6;
continue;
}
if(Prob[i][j].first==-1)
{
spa(ns);printf("*");
ns=6;
continue;
}
int nr=6,a=0,b=0;
if(Prob[i][j].first!=-2&&(a=Con[Prob[i][j].first].Goal)>=10)ns-=3;
else ns-=2;
if(Prob[i][j].second!=-2&&(b=Con[Prob[i][j].second].Goal)>=10)nr-=3;
else nr-=2;
spa(ns);printf("(%d,%d)",a,b);
ns=nr;
}
printf("\n");
}
}
int main()
{
for(int i=0;i<=5;i++)
{
char a[]="test5.txt";
char b[]="text5ans.txt";
a[4]=i+'0';
b[4]=a[4];
// printf("\n\n%s",b);
freopen(a,"r",stdin);
freopen(b,"w",stdout);
Init();
Print(0);
if(Solve()){printf("Exists one solution\n");Print(1);}
else printf("No solution found\n");
}
return 0;
} /*
test0.txt
9 8
* * *(20,0) (7,0) * * *
* *(21,4) 0 0 (8,0) * *
* (0,21)0 0 0 0(27,0) *
*(12,11)0 0 (0,15)0 0 (16,0)
(0,16)0 0 * * (0,8) 0 0
(0,8) 0 0(15,0) *(20,16)0 0
* (0,11)0 0 (9,8) 0 0 *
* * (0,20)0 0 0 0 *
* * * (0,17) 0 0 * * test1.txt 4 4
* (23,0)(21,0) (7,0)
(0,20) 0 0 0
(0,19) 0 0 0
(0,12) 0 0 0
test2.txt 5 5
*(16,0) (7,0) * *
(0,9) 0 0(24,0) *
(0,20)0 0 0 (4,0)
* (0,12) 0 0 0
* * (0,10)0 0
test3.txt 9 8
* (16,0) (6,0) * * (8,0)(29,0) *
(0,13) 0 0 (15,0)(16,13) 0 0 *
(0,28) 0 0 0 0 0 0 (11,0)
* * (30,15) 0 0 (0,3) 0 0
* (16,8) 0 0 * (22,14) 0 0
(0,14) 0 0 * (9,17) 0 0 *
(0,13) 0 0 (5,10) 0 0 (12,0) (8,0)
* (0,32) 0 0 0 0 0 0
* (0,11) 0 0 * (0,12) 0 0 test4.txt 13 13
* (16,0) (7,0) * (16,0) (17,0) * * (10,0) (16,0) * * *
(0,9) 0 0 (0,10) 0 0 (3,0) (0,9) 0 0 * * *
(0,10) 0 0 (16,12) 0 0 0 (3,10) 0 0 * * *
* (0,17) 0 0 0 (0,6) 0 0 0 (16,0) * * *
* * (0,12) 0 0 (17,0) (6,14) 0 0 0 (6,0) * *
* * (3,0) (6,13) 0 0 0 (7,0) (0,10) 0 0 (16,0) *
* (0,4) 0 0 (0,14) 0 0 0 (16,0) (0,10) 0 0 *
* (0,3) 0 0 (16,0) (0,12) 0 0 0 (35,9) 0 0 *
* * (0,9) 0 0 (10,0) (17,19) 0 0 0 (16,0) * *
* * * (0,21) 0 0 0 (16,0) (0,14) 0 0 (24,0) *
* * * * (16,17) 0 0 0 (4,24) 0 0 0 (3,0)
* * * (0,10) 0 0 (0,19) 0 0 0 (0,11) 0 0
* * * (0,11) 0 0 * (0,7) 0 0 (0,8) 0 0
test5.txt 15 15
* * * (35,0) (17,0) (6,0) * (17,0) (6,0) * (16,0) (6,0) * * *
* * (0,15) 0 0 0 (0,12) 0 0 (28,9) 0 0 * * *
* * (4,18) 0 0 0 (16,26) 0 0 0 0 0 (4,0) * *
* (0,9) 0 0 (0,10) 0 0 (4,4) 0 0 (3,4) 0 0 (39,0) *
* (0,12) 0 0 (16,0) (0,12) 0 0 (17,5) 0 0 (0,9) 0 0 (3,0)
* (4,0) (22,12) 0 0 (24,0) (0,19) 0 0 0 0 * (16,5) 0 0
(0,10) 0 0 (0,17) 0 0 (41,0) (0,10) 0 0 (23,0) (0,18) 0 0 0
(0,4) 0 0 (17,0) (0,9) 0 0 * (0,7) 0 0 (0,14) 0 0 (16,0)
* (4,13) 0 0 (0,17) 0 0 (4,0) (0,14) 0 0 (3,0) (0,16) 0 0
(0,13) 0 0 0 * (17,5) 0 0 (16,0) (0,9) 0 0 (16,15) 0 0
(0,3) 0 0 (16,0) (0,25) 0 0 0 0 (3,0) (0,6) 0 0 (16,0) *
* (0,11) 0 0 (24,15) 0 0 (7,11) 0 0 (6,0) (0,10) 0 0 *
* * (0,16) 0 0 (4,9) 0 0 (16,3) 0 0 (16,11) 0 0 *
* * * (0,27) 0 0 0 0 0 (0,13) 0 0 0 * *
* * * (0,12) 0 0 (0,10) 0 0 (0,14) 0 0 0 * *
*/

  

05-12 14:17