【wikioi】1174靶形数独

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[n][0];
	y=b[n][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[n][0]=i;
				b[n][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[n]=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];
		 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;
}

 

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值