[搜索顺序] POJ 1165 [IOI 1994] The Primes

论文:王知昆--搜索顺序的选择


根据元素取值范围和制约力确定搜索顺序

1、最后一行和最后一列是取值范围最小的搜索元素,而且它们对其他所有的元素都有一定的制约力,因此要放在搜索序列的最前面。

2、两条对角线同样影响到其他所有的搜索元素,制约力在剩下的格子中是最大的,因此也应当优先搜索。

3、剩下的行列依据它们取值范围的大小确定搜索顺序。


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

const int lstx[]={
  1,2,3,4,5,5,5,5,5,2,3,4,2,4,4,4,1,3,3,3,1,2,1,2
};
const int lsty[]={
  5,5,5,5,5,1,2,3,4,2,3,4,4,2,1,3,4,4,2,1,2,3,3,1
};
const int tag[]={
  0,0,0,0,1,0,0,0,2,0,0,4,0,3,0,2,0,1,0,2,1,0,1,2
};

struct Ans{
  int a[6];
  bool operator < (const Ans &B) const {
    for (int i=1;i<=5;i++){
      if (a[i]<B.a[i]) return 1;
      if (a[i]>B.a[i]) return 0;
    }
    return 0;
  }
}ans[10005];
int tot;

const int maxn=100000;

int vst[maxn+5],prime[maxn+5],num;

inline void Pre(){
  for (int i=2;i<maxn;i++){
    if (!vst[i]) prime[++num]=i;
    for (int j=1;j<=num && (long long)prime[j]*i<maxn;j++){
      vst[prime[j]*i]=1;
      if (i%prime[j]==0) break;
    }
  }
}

int s,a[10][10];

inline bool check(int x,int y){
  if (x==1||y==1) if (!a[x][y]) return 0;
  int flag,tem,sum;
  flag=0,tem=0,sum=0;
  for (int j=1;j<=5 && !flag;j++)
    if (a[x][j]!=-1) tem=tem*10+a[x][j],sum+=a[x][j]; else flag=1;
  if (!flag)
    if (vst[tem] || sum!=s)
      return 0;
  flag=0,tem=0,sum=0;
  for (int i=1;i<=5 && !flag;i++)
    if (a[i][y]!=-1) tem=tem*10+a[i][y],sum+=a[i][y]; else flag=1;
  if (!flag)
    if (vst[tem] || sum!=s)
      return 0;
  if (x==y){
    flag=0,tem=0,sum=0;
    for (int i=1;i<=5 && !flag;i++)
      if (a[i][i]!=-1) tem=tem*10+a[i][i],sum+=a[i][i]; else flag=1;
    if (!flag)
      if (vst[tem] || sum!=s)
	return 0;
  }
  if (x+y==6){
     flag=0,tem=0,sum=0;
     for (int i=5;i && !flag;i--)
       if (a[i][6-i]!=-1) tem=tem*10+a[i][6-i],sum+=a[i][6-i]; else flag=1;
     if (!flag)
       if (vst[tem] || sum!=s)
	 return 0;
  }
  return 1;
}

void dfs(int t){
  if (t==24){
    ++tot;
    for (int i=1;i<=5;i++){
      int tem=0;
      for (int j=1;j<=5;j++)
	tem=tem*10+a[i][j];
      ans[tot].a[i]=tem;
    }
    return;
  }
  int x=lstx[t],y=lsty[t];
  int sum=0;
  if (tag[t]==1){
    sum=0;
    for (int i=1;i<=5;i++) if (a[i][y]!=-1) sum+=a[i][y];
    a[x][y]=s-sum;
    if (a[x][y]>=0 && a[x][y]<=9 && check(x,y))
      dfs(t+1);
    a[x][y]=-1;
  }else if (tag[t]==2){
    sum=0;
    for (int j=1;j<=5;j++) if (a[x][j]!=-1) sum+=a[x][j];
    a[x][y]=s-sum;
    if (a[x][y]>=0 && a[x][y]<=9 && check(x,y))
      dfs(t+1);
    a[x][y]=-1;
  }else if (tag[t]==3){
    sum=0;
    for (int i=1;i<=5;i++) if (a[i][6-i]!=-1) sum+=a[i][6-i];
    a[x][y]=s-sum;
    if (a[x][y]>=0 && a[x][y]<=9 && check(x,y))
      dfs(t+1);
    a[x][y]=-1;
  }else if (tag[t]==4){
    sum=0;
    for (int i=1;i<=5;i++) if (a[i][i]!=-1) sum+=a[i][i];
    a[x][y]=s-sum;
    if (a[x][y]>=0 && a[x][y]<=9 && check(x,y))
      dfs(t+1);
    a[x][y]=-1;
  }else{
    for (int i=(x==1||y==1||x==5||y==5)?1:0;i<=9;i+=(x==5||y==5)?2:1){
      a[x][y]=i;
      if (check(x,y))
	dfs(t+1);
      a[x][y]=-1;
    }
  }
}

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  Pre();
  memset(a,-1,sizeof(a));
  scanf("%d%d",&s,&a[1][1]);
  dfs(0);
  sort(ans+1,ans+tot+1);
  for (int i=1;i<=tot;i++,putchar('\n'))
    for (int j=1;j<=5;j++)
      printf("%d\n",ans[i].a[j]);
  return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值