[ZOJ 2961] Spinlock [搜索]

18 篇文章 0 订阅
17 篇文章 0 订阅

已知一个密码锁,最多有6位数字,每个数字都是10进制数。有100个按钮,每个按钮可以让某些数字转动若干次。你只能通过按按钮来转动密码锁。问最小的按按钮的次数,输出字典序最小的序列。

搜索,BFS即可。把每个状态当成一个点,复杂度略微有点高..最坏有10^8条边...但是好像不会到这么坏...

#include <cstdio>
#include <algorithm>

using namespace std;

const int INF=~0u>>1;

int minv[1000000];
int from[1000000];
int que[1000000];
int ans[1000000];
int a[100];
int pow[7];
int d,n,s,t,p,q,m;

inline int calTo(int i,int j) {
	int ans=0,k;
	for (k=0;k<d;k++) {
		ans+=(i+j)%10*pow[k];
		i/=10;
		j/=10;
	}
	return ans;
}
inline int cal(int i,int j) {
	int ans=0,k;
	for (k=0;k<d;k++) {
		ans+=(j-i+2000000)%10*pow[k];
		i/=10;
		j/=10;
	}
	return ans;
}
inline void print(int x) {
	for (int k=d-1;k>=0;k--) {
		printf("%d",x/pow[k]%10);
	}
	printf("\n");
}

int main() {
	int i,j,k;
	pow[0]=1;
	for (i=0;i<6;i++) pow[i+1]=pow[i]*10;
	while (scanf("%d%d",&d,&n)!=EOF) {
		for (i=0;i<n;i++) scanf("%d",&a[i]);
		sort(a,a+n);
		m=pow[d];
		scanf("%d%d",&s,&t);
		for (i=0;i<m;i++) minv[i]=INF;
		p=q=0;
		que[q++]=s;
		minv[s]=0;
		while (p!=q&&que[p]!=t) {
			i=que[p++];
			//printf("from %d\n",i);
			for (j=0;j<n;j++) {
				k=calTo(i,a[j]);
				//printf(" add %d = %d\n",a[j],k);
				if (minv[k]==INF) {
					minv[k]=minv[i]+1;
					from[k]=i;
					que[q++]=k;
				}
			}
		}
		if (minv[t]==INF) printf("-1\n");
		else {
			p=0;q=t;
			while (q!=s) {
				//printf("-- %d + %d -> %d\n",from[q],cal(from[q],q),q);
				ans[p++]=cal(from[q],q);
				q=from[q];
			}
			printf("%d\n",p);
			while (p--) {
				print(ans[p]);
			}
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值