您的位置:首页 > 编程语言 > C语言/C++

【wikioi】1174靶形数独

2014-05-14 21:23 387 查看
DFS爆搜,相当慢……

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
const int M = 10;
const int p[10][10] = {
{0,0,0,0,0,0,0,0,0,0},
{0,6,6,6,6,6,6,6,6,6},
{0,6,7,7,7,7,7,7,7,6},
{0,6,7,8,8,8,8,8,7,6},
{0,6,7,8,9,9,9,8,7,6},
{0,6,7,8,9,10,9,8,7,6},
{0,6,7,8,9,9,9,8,7,6},
{0,6,7,8,8,8,8,8,7,6},
{0,6,7,7,7,7,7,7,7,6},
{0,6,6,6,6,6,6,6,6,6}
};
const int w[10][10]={
{0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,2,2,2,3,3,3},
{0,1,1,1,2,2,2,3,3,3},
{0,1,1,1,2,2,2,3,3,3},
{0,4,4,4,5,5,5,6,6,6},
{0,4,4,4,5,5,5,6,6,6},
{0,4,4,4,5,5,5,6,6,6},
{0,7,7,7,8,8,8,9,9,9},
{0,7,7,7,8,8,8,9,9,9},
{0,7,7,7,8,8,8,9,9,9}
};
int a[M][M];
int line[M][M];
int column[M][M];
int pane[M][M];
int b[M*M+9][2];
long long ans=0;
int t;
int find1(long long x,long long tot){//x为空点的数量
int x1,y1,y;
int i,j;
if(x==0){
if(tot>ans){
ans=tot;

}
return 0;
}
t++;
if(t>12345000) return 0;//卡点小时
for(i=1;i<M;i++){

if(line[i][b[x][0]]==0&&column[i][b[x][1]]==0&&pane[w[b[x][0]][b[x][1]]][i]==0){//这个空点填这个数字 不在该行,不在该列,不在该宫

x1=b[x][0];
y1=b[x][1];
y=w[x1][y1];

line[i][x1]=1;
column[i][y1]=1;
pane[y][i]=1;

a[x1][y1]=i;
find1(x-1,tot+a[x1][y1]*p[x1][y1]);

line[i][x1]=0;
column[i][y1]=0;
pane[y][i]=0;
}
}

return 0;
}

int count;
int tot;

int main(){
int i,j,k;
for(i=1;i<M;i++){
for(j=1;j<M;j++){
scanf("%d",&a[i][j]);
if(a[i][j]){
line[a[i][j]][i]=1;
column[a[i][j]][j]=1;
pane[w[i][j]][a[i][j]]=1;
tot+=a[i][j]*p[i][j];
}
else {
b[++count][0]=i;
b[count][1]=j;
}
}
}
find1(count,tot);
if(ans==0) ans=-1;
printf("%d\n",ans);
system("pause");
return 0;

}

加了一些优化,使用集合来进行表示,比单纯地暴搜快了一倍

 

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

int hang[10]={0};//表示在第i行的数字j是否出现
int lie[10]={0};
int gong[10]={0};
int sit[10][10]={
{0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,2,2,2,3,3,3},
{0,1,1,1,2,2,2,3,3,3},
{0,1,1,1,2,2,2,3,3,3},
{0,4,4,4,5,5,5,6,6,6},
{0,4,4,4,5,5,5,6,6,6},
{0,4,4,4,5,5,5,6,6,6},
{0,7,7,7,8,8,8,9,9,9},
{0,7,7,7,8,8,8,9,9,9},
{0,7,7,7,8,8,8,9,9,9},
};
int score[10][10]={
{0,0,0,0,0,0,0,0,0,0},
{0,6,6,6,6,6,6,6,6,6},
{0,6,7,7,7,7,7,7,7,6},
{0,6,7,8,8,8,8,8,7,6},
{0,6,7,8,9,9,9,8,7,6},
{0,6,7,8,9,10,9,8,7,6},
{0,6,7,8,9,9,9,8,7,6},
{0,6,7,8,8,8,8,8,7,6},
{0,6,7,7,7,7,7,7,7,6},
{0,6,6,6,6,6,6,6,6,6},
};
int map[10][10]={0};

int b[82][2]={0};
int ans=0;

void solve(int n,int r)
{
if(n==0)
{
ans=(r>ans?r:ans);
return;
}
int x,y;
x=b
[0];
y=b
[1];
int a,b;
a=hang[x]|lie[y]|gong[sit[x][y]];//求并集
for(int i=1;i<=9;i++)
{
b=~(1<<i)*-1;
if((a&b)==0)//双方没有共同元素
{
hang[x]+=(1<<i),lie[y]+=(1<<i),gong[sit[x][y]]+=(1<<i);
r+=score[x][y]*i;
solve(n-1,r);
r-=score[x][y]*i;
hang[x]-=(1<<i),lie[y]-=(1<<i),gong[sit[x][y]]-=(1<<i);
}
}
}

int main(void)
{
freopen("in.txt","r",stdin);
int r=0;
int n=0;
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
scanf("%d",&map[i][j]);
if(map[i][j])
{
hang[i]+=(1<<map[i][j]);
lie[j]+=(1<<map[i][j]);
gong[sit[i][j]]+=(1<<map[i][j]);
r+=score[i][j]*map[i][j];
}
else
{
n++;
b
[0]=i;
b
[1]=j;
}
}
}
solve(n,r);
if(ans==0)
ans=-1;
printf("%d\n",ans);

return 0;
}
/*
将每一个行、列或九宫的数据用集合来表示

*/


 

加上了启发式搜索函数

/*-------------------------------------
DFS. + 启发函数.
-------------------------------------*/
//----------Source Program-------------
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define MAX(a,b) a>b?a:b
using namespace std;

int Map[10][10]   = {0};   //这个就不用解释了吧
int Nine[10][10]  = {0};    //小九宫格里每个数的使用标记,小九宫格的编号左到右,上到下,1,2,3,4,5,6,7,8,9
int Line[10][10]  = {0};    //行上每个数的使用标记
int Row[10][10]   = {0};   //列上每个数的使用标记
int FQueL[10]     = {0};    //被启发后的行访问顺序
int FQueR[10]     = {0};    //被启发后的列访问顺序
int Value[10][10] = {0};    //地图各点的价值因子
int QueL[81]      = {0};     //
int QueR[81]      = {0};     //与上面那个,是根据启发后制定的搜索顺序的行列参数
int QLen  = 0;                  //搜索队列的长度
int Ans   = -1;                 //最优解
int Count = 0;                  //废物变量,纪念原来我错误的写法,懒得删掉了

int Swap(int *a,int *b)
{
int o=*a;
*a=*b;
*b=o;
}

void Heu()  //启发函数
{
for(int i=1;i<=9;++i){
FQueL[i] = i;
FQueR[i] = i;
}

for(int i=1;i<=8;++i)
for(int j=9;j>=i+1;--j){
if(Line[FQueL[j]][0] > Line[FQueL[j-1]][0])
Swap(&FQueL[j],&FQueL[j-1]);
if(Row[FQueR[j]][0] > Row[FQueR[j-1]][0])
Swap(&FQueR[j],&FQueR[j-1]);
}
for(int i=1;i<=9;++i)
for(int j=1;j<=9;++j)
if(Map[FQueL[i]][FQueR[j]] == 0){
QueL[QLen]=FQueL[i];
QueR[QLen]=FQueR[j];
QLen++;
}
// for(int i=1;i<=9;++i)
//      cout<<FQueL[i]<<' '<<Line[FQueL[i]][0]<<' '<<FQueR[i]<<' '<<Row[FQueR[i]][0]<<endl;
}

int belong(int i,int j)     //判断行列参数为i,j的点属于哪一个九宫格。
{
int xt = 0,yt = 0;
for(int k=6;k>=0;k-=3){
if(i-k>0){xt=(k+3)/3;break;}
}
for(int k=6;k>=0;k-=3){
if(j-k>0){yt=(k+3)/3;break;}
}
//   cout<<xt<<' '<<yt<<' '<<xt+(yt-1)*3<<endl;
//   cout<<i<<' '<<j<<' '<< yt+(xt-1)*3 <<endl;
return yt+(xt-1)*3;
}

int Score()           //成绩计算
{
int Temp = 0;
for(int i=1;i<=9;++i)
for(int j=1;j<=9;++j)
Temp += Map[i][j]*Value[i][j];
Ans = MAX(Temp,Ans);
//  cout<<Ans<<endl;
}

int Dfs(int step)      //深度优先搜索主体
{
//  cout<<step<<' '<<81-Count<<endl;
//  for(int i=1;i<=9;++i,cout<<endl)
//    for(int j=1;j<=9;++j)
//      cout<<Map[i][j]<<' ';
if(step == QLen){Score();return 0;}
if(!Map[QueL[step]][QueR[step]])
for(int k=1;k<=9;++k){
if(!Nine[belong(QueL[step],QueR[step])][k])
if(!Line[QueL[step]][k] && !Row[QueR[step]][k]){
//Heu();
//                cout<<FQueL[i]<<' '<<FQueR[j]<<' '<<k<<endl;
Map[QueL[step]][QueR[step]] = k;
Nine[belong(QueL[step],QueR[step])][k] = 1;
Line[QueL[step]][k]=Row[QueR[step]][k] = 1;
Line[QueL[step]][0]++;Row[QueR[step]][0]++;
Dfs(step+1);
Map[QueL[step]][QueR[step]] = 0;
Nine[belong(QueL[step],QueR[step])][k] = 0;
Line[QueL[step]][k]=Row[QueR[step]][k] = 0;
Line[QueL[step]][0]--;Row[QueR[step]][0]--;
}
}
return 0;
}

int main()
{
for(int i=1;i<=5;++i)
for(int j=1+(i-1);j<=9-(i-1);++j){
Value[i][j] = 6+(i-1);
Value[9-(i-1)][j] = 6+(i-1);
Value[j][9-(i-1)] = 6+(i-1);
Value[j][i] = 6+(i-1);
}   //init value    对价值表的初始,好像其他人都是直接用{}初始的.......
//  for(int i=1;i<=9;++i,cout<<endl)
//    for(int j=1;j<=9;++j)
//       cout<<Value[i][j]<<' ';
for(int i=1;i<=9;++i)
for(int j=1,x,y;j<=9;++j){
scanf("%d",&Map[i][j]);
if(Map[i][j] != 0 ){
Line[i][Map[i][j]] = 1;
Line[i][0]++;
Row[j][Map[i][j]]  = 1;
Row[j][0]++;
Nine[belong(i,j)][Map[i][j]] = 1;
Count++;
}
}

//  for(int i=1;i<=9;++i,cout<<endl)
//   for(int j=1;j<=9;++j)
//      cout<<Nine[i][j];

Heu();
Dfs(0);

cout<<Ans;
return 0;
}

DLX镇楼
<pre class="cpp" name="code" snippet_file_name="blog_20140514_3_8357491" code_snippet_id="345642">#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxc=324+10;
const int maxr=729+10;
const int maxnode=maxr*4+maxc;
const int p[9][9]=
{
{6,6,6,6,6,6,6,6,6},
{6,7,7,7,7,7,7,7,6},
{6,7,8,8,8,8,8,7,6},
{6,7,8,9,9,9,8,7,6},
{6,7,8,9,10,9,8,7,6},
{6,7,8,9,9,9,8,7,6},
{6,7,8,8,8,8,8,7,6},
{6,7,7,7,7,7,7,7,6},
{6,6,6,6,6,6,6,6,6}
};
struct DLX
{
int n,sz;
int S[maxc];
int row[maxnode],col[maxnode],get[maxnode];
int L[maxnode],R[maxnode],U[maxnode],D[maxnode];
int ans;
void init(int n)
{
this->n=n;
for(int i=0;i<=n;i++)
{
U[i]=D[i]=i;
L[i]=i-1;
R[i]=i+1;
}
R
=0;
L[0]=n;
sz=n+1;
memset(S,0,sizeof S);
}
void addRow(int r,vector<int> columns,int _get)
{
int first=sz;
for(int i=0;i<columns.size();i++)
{
int c=columns[i];
L[sz]=sz-1;
R[sz]=sz+1;
D[sz]=c;
U[sz]=U[c];
D[U[c]]=sz;
U[c]=sz;
row[sz]=r;
col[sz]=c;
get[sz]=_get;
S[c]++;
sz++;
}
R[sz-1]=first;
L[first]=sz-1;
}
#define FOR(i,A,s) for(int i=A[s];i!=s;i=A[i])
void remove(int c)
{
L[R[c]]=L[c];
R[L[c]]=R[c];
FOR(i,D,c)
FOR(j,R,i)
{
U[D[j]]=U[j];
D[U[j]]=D[j];
S[col[j]]--;
}
}
void restore(int c)
{
FOR(i,U,c)
FOR(j,L,i)
{
S[col[j]]++;
U[D[j]]=j;
D[U[j]]=j;
}
L[R[c]]=c;
R[L[c]]=c;
}
void dfs(int d,int score)
{
if(R[0]==0)
{
ans=max(ans,score);
return;
}
int c=R[0];

b75b
FOR(i,R,0)
if(S[i]<S[c])
c=i;
remove(c);
FOR(i,D,c)
{
FOR(j,R,i)
remove(col[j]);
dfs(d+1,score+get[i]);
FOR(j,L,i)
restore(col[j]);
}
restore(c);
}
int solve()
{
ans=-1;
dfs(0,0);
return ans;
}
};
DLX solver;
const int SLOT=0;
const int ROW=1;
const int COL=2;
const int SUB=3;
int encode(int a,int b,int c)
{
return a*81+b*9+c+1;
}
int puzzle[9][9];
int main()
{
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
scanf("%d",&puzzle[i][j]);
solver.init(324);
for(int r=0;r<9;r++)
for(int c= 0;c<9;c++)
for(int v=0;v<9;v++)
if(puzzle[r][c]==0||puzzle[r][c]==v+1)
{
vector<int> columns;
columns.push_back(encode(SLOT,r,c));
columns.push_back(encode(ROW,r,v));
columns.push_back(encode(COL,c,v));
columns.push_back(encode(SUB,(r/3)*3+c/3,v));
solver.addRow(encode(r,c,v),columns,p[r][c]*(v+1));
}
printf("%d\n", solver.solve());
return 0;
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  DLX c++ 启发式搜索