【2016 泉市教科】密码锁

密码锁

问题描述

  小 A 退了课程和社团之后,感到了一身轻松。正逢秋高气爽,他约上了妹子小 B 到郊外游玩。一路上,他们愉快地讨论着基于连通性的状态压缩动态规划、线段跳表、树链剖分等人民群众喜闻乐见的问题,愉快地穿梭于树、精美的图和仙人掌之中。这时他们的目光被一个数字密码锁吸引了,这个密码锁只有 0 和 1 两个按键和一个长度为K 的显示屏。边上还很友好地附着一张说明书,告诉他们这一密码锁是滚动的,即当输入第K+1 位数字时,最先输入的数字将会从屏幕上删去,新输入的数字将会成为屏幕上的第 K 位数字。当这个长度为 K 的显示屏上呈现出正确的 K 位密码时,他们将会获得神秘的宝藏;但是如果他们尝试了两个相同的密码,这个密码锁将会爆炸。
  小 A 已经跃跃欲试了,想在小 B 面前出出风头。他希望能够获得一个输入序列,使得试过的密码数最多,同时输入的过程中不会爆炸。为了显得更优雅,小 A 希望这一序列的字典序最小,其中 0 小于 1。你知道这一序列是什么吗?

输入

  输入文件名为 lock.in。
  一个整数 K。

输出

  输出文件名为 lock.out。
  一个整数 M 和一个 M 位二进制串,由一个空格分隔。这二进制串是小 A 输入的最小字典序的二进制串。

Sample Input

3

Sample Output

10 0001011100

样例说明

  尝试的 8 个 3 位密码分别是 000、001、010、101、011、111、110 和 100。注意前后是相邻的。长度为 3 的二进制串总共只有 8 种,所以尝试了 8 种一定是可能的最大值。

数据范围

  对于 100%的数据,2≤K≤11。

题解

  反正怎么看我都想打表 - 最后还是打了
  不过我们对搜索过程优化一下,还是可以压缩到1S以内的。
  由题目我们可以看出来,一旦搜索到的当前方位出现了重复的数字,就应该立即退出该层循环,返回上一层。由于该题要求字典序最下,我们优先搜索‘0’,而搜索过程中的判重,可以将二进制转换成十进制判重即可。并且从题目中,我们可以推出所求字典长度为(2^(k) ) +k-1。
  附上Pascal代码:
  

program baoli;
var a,b:array[0..100000] of integer;
    f:Array[0..5000] of boolean;
    i,j,k,g,n,max,min:longint;

function power(a,b:longint):longint;//power函数
var ans,i,j:longint;
begin
    ans:=1;
    if (b=0) and (a >0) then exit(1);
    for i:=1 to b do
       ans:=ans*a;
    exit(ans);
end;

function change(l,r:longint):longint; //转成二进制
var i,j,ans:longint;
begin
   ans:=0;
   for i:=l to r do
   begin
     ans:=ans+a[i] * power(2,i-l);
   end;
   exit(ans);
end;


procedure search(k:longint);//dfs
var i,j,tmp,cnt:longint;
    flag:boolean;
begin
if k<=g then
  for j:=0 to 1 do
  begin
    a[k]:=j;
    flag:=true;
    fillchar(f,sizeof(f),true);
    for i:=1 to k-n+1 do
    begin
      tmp:=change(i,i+n-1);
      if f[tmp] then
      begin
        inc(cnt);
        f[tmp]:=false;
      end
      else
      begin
        flag:=false;//flag标记当前是否已经出现重复数字,有则为false
        break;
      end;
    end;
    if flag then//如果flag为true,即无重复数字再继续搜索
    search(k+1);
    a[k]:=0;
  end
else
begin
  fillchar(f,sizeof(f),true);
  cnt:=0;
  for i:=1 to g-n+1 do
  begin
    tmp:=change(i,i+n-1);
    if f[tmp] then
    begin
      inc(cnt);
      f[tmp]:=false;
    end
    else
    begin
      exit;
    end;
  end;
  if cnt>max then begin max:=cnt;b:=a;end;
  if cnt =  g+1-n then
  begin
    for i:=1 to g do
      write(a[i]);
      close(output);
    halt;
  end;
end;
end;

begin

  assign(input,'lock.in');reset(input);
  assign(output,'lock.out');rewrite(output); 
  read(n);
  max:=-maxlongint;
  fillchar(a,sizeof(a),0);
  g:=power(2,n) + n -1;
  write(g,' ');
  search(1);
  for i:=1 to g do
    write(b[i]);
  close(output);
end.

不过这题还可以利用欧拉路的思想来求解,压栈出解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值