Kakuro - Cross Sums

问题如下 一个简单的例子

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

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

我们考虑用GAC加速。

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

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

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

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

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

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

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

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

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

下面给出伪代码

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

下面给出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 * *
*/

  

最新文章

  1. user initialization list vs constructor assignment
  2. Android应用开发项目结构分析
  3. SqlServer删除登录账户
  4. sed实例精解--例说sed完整版
  5. Java获取当前进程的所有线程
  6. iOS开发篇-申请开发者账号流程
  7. DropDownListFor使用ViewData进行绑定的示例
  8. java 分解质因数 基础增强
  9. 201521123019 《Java程序设计》第2周学习总结
  10. shell脚本里面相互调用时路径不要用pwd获取
  11. HTML5利用canvas,把多张图合并成一张图片
  12. 【原创】JAVA面试解析(有赞一面)
  13. flask微电影系统开发中上下文处理器
  14. springboot用户登陆密码两次md5加密
  15. OpenCV3计算机视觉Python语言实现笔记(五)
  16. ESXi去掉 SSH已经启用的警告信息
  17. MSSQL数据库优化经验
  18. leecode第七十题(爬楼梯)
  19. git hub 使用心得
  20. Gitlab-通过API管理问题

热门文章

  1. 《深入理解mybatis原理》 MyBatis的二级缓存的设计原理
  2. 【Java TCP/IP Socket】深入剖析socket——数据传输的底层实现
  3. Spring MVC集成Spring Data Reids和Spring Session实现Session共享出现:No bean named &#39;springSessionRepositoryFilter&#39; available
  4. Matlab多项式拟合測试
  5. docker下用keepalived+Haproxy实现高可用负载均衡集群
  6. 用 centrifugo 搭建 消息推送服务器 docker + rancher 搭建
  7. v-if v-else-if v-else
  8. Type cannot use &#39;try&#39; with exceptions disabled
  9. 【转载】分布式RPC框架性能大比拼
  10. 标准C头文件