1269: 爱看电视的LsF+遥控器 dfs+剪枝

1269: 爱看电视的LsF

时间限制: 1 秒  内存限制: 64 MB
提交: 292  解决: 70
提交  状态 
题目描述

LsF(刘师傅)非常喜欢看电视!
不幸的是,遥控器上的一些数字按钮坏了。 但他灵光一闪,如果他不能直接输入他想要看到的频道的号码,那么他可以先输入其他号码,再通过按下按钮+ 和- (这两个按钮由24K钛合金制成,永远不会坏)的方式到达所需的频道。 按钮+将数字增加1,按钮-将数字减少1。当然他依然可以使用那些完好无损的数字按钮输入号码。
他最初在第S频道,他想看第T频道。他想知道由ST频道所需的最少按钮按压次数。

输入

输入包含多组数据。
对于每组数据,第一行是三个整数n,S,T(n≤10,0≤S,T≤500,000。 第二行是n个数字 a1,a2,...,an,表示数字 ai键已经坏了 (0≤ai≤9,aiaj when ij)。

输出

输入包含多组数据。
对于每组数据,第一行是三个整数n,S,T(n≤10,0≤S,T≤500,000。 第二行是n个数字 a1,a2,...,an,表示数字 ai键已经坏了 (0≤ai≤9,aiaj when ij)。

样例输入
10 1 100
0 1 2 3 4 5 6 7 8
 9
9 1 100
0 1 2 3 4 5 6 7 8
样例输出
99
3
 
代码:用了深搜,最后发现这样做给自己挖了很多坑,但是缝缝补补的还是过了。。。思路是深搜尽可能接近要搜的频道。。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
int vis[15];
int ans[500000];
int   n,S,T;
int res;
void dfs(int sum,int count)
{ //  printf("********************\n");
//  for(int i=0;i<count;i++)  printf("%d",ans[i]);
//  printf("sum==%d count==%d res==%d\n",sum,count,res);
    if(count>res) return ;//超过当前最优,返回 
    if(sum==0&&count>10) return ;
    if(sum==T)//到达T,与当前最少按键次数比较 
    { 
//      for(int i=0;i<count;i++)  printf("%d",ans[i]);
//      printf("sum==%d count==%d res==%d ==\n",sum,count,res);
        res=min(res,count);
//      printf("sum==%d count==%d res==%d ==\n",sum,count,res);
        return ;
    }
    if(sum>T)//超了以后按减 
    {
//       for(int i=0;i<count;i++)  printf("%d",ans[i]);
//       printf("\tsum==%d count==%d res==%d   >>%d\n",sum,count,res,count+sum-T);
        dfs(T,count+sum-T);
        return ;
    }
    for(int i=0;i<=9;i++)//按数字 
    {
        if(vis[i]) continue;
        ans[count]=i;
        if(count+1<res) dfs(sum*10+i,count+1);
    }
    if(count!=0) ans[count]=-1,dfs(T,count+T-sum);//按加 ,在当前所搜的台的基础上,sum=0的时候需要特判 
}
int main()
{
    while(~scanf("%d%d%d",&n,&S,&T))
    {
        memset(vis,false,sizeof(vis));
        for(int i=0;i<n;i++)
        {
            int a;
            scanf("%d",&a);
            vis[a]=true;
        }
//      if(S==0&&T==500000)
//      {
//          printf("1\n");
//          continue;
//      }
        if(S==T) 
        {
            printf("0\n");
            continue ;
        }
        int temp=S;
        for(int i=0;i<10;i++) 
        {
            if(!vis[i]&&i<temp) temp=i;
        }
        if(T==0)//特判,否则T==0影响dfs()结束条件 
        {
              
            //if(!vis[0])   printf("1\n");
            if(temp==S)   printf("%d\n",temp);
            else  printf("%d\n",temp+1);
            continue ;
        }
        res=5000000;
        dfs(0,0);
        res=min(res,(int)fabs(T-S));
        printf("%d\n",res);
    }
}

1617 : 遥 控 器

时间限制:1 Sec 内存限制:128 MiB
提交:43 答案正确:15

提交 状态 讨论区

题目描述

Dr.Kong 有一台高级电视机,这台电视机可以接受100个频道(从099编号)。电视的配套遥控器有13个按钮:

1     3   

  5     

  8   9

—  0

当按""键时,当前频道编号会增加1(如果当前为99频道,则会切换到0频道)。如果按""键,当前频道编号会减小1(如果当前为0频道,则会切换到99频道)当要切换到0~9频道时,可以直接在遥控器上按相应的键。当要切换到10~99频道时,可以先按""键,然后按2个与频道编号相对应的数字键(即先按与频道编号的十位数字相对应的键,然后按与个位数字相对应的键)

由于遥控器长时间的使用和某些未知原因,遥控器上的某些键已经坏了,不能再起作用了。现在你的任务是,能否告诉Dr.Kong,如何用最少的按键次数来将频道从编号X切换到编号Y

输入

第一行: N  表示有N组测试数据。  (1<=N<=5)

对每组测试数据有5行,前4行包含遥控器上每个按键的信息。0表示对应的键坏了,1表示对应的键可以使用。5行包含2个整数,分别是X 和 Y    (0 <X <= 99<Y <= 99)

输出

对每组测试数据输出一行,即将频道从编号X切换到编号Y所需要的最小按键次数。如果不可能将频道从编号切换到编号Y,则输出-1.

样例输入

复制
2
0 0 1 1 
1 1 1 1
1 1 1
1 1
23 52
1 1 1 0
1 1 1 0
1 0 1
0 1
23 52

样例输出

复制
4
-1
代码:广搜,是所搜的频道尽可能逼近目标频道。。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<math.h>
using namespace std;
int n,S,T;
bool vis[15];
// 0 1 2 3-------1 2 3 +
// 4 5 6 7-------4 5 6 -
// 8 9 10 -------8 9 10
// 11 12  ------ —0 
bool sub,add,as;
int res;
int maxx;
struct Node 
{
	int sum;
	int count;
	Node(){}
    Node(int _sum,int _count)
    {
    	sum=_sum;
    	count=_count;
	}
};
void bfs()
{
	queue<Node> q;
	Node node;
	node.sum=0;
	node.count=0;
	q.push(node);
	maxx=0;
	while(!q.empty())
	{  if(q.size()>maxx) maxx=q.size();
		node =q.front();
		q.pop();
		int sum=node.sum;
		int count=node.count;
//		printf("q.size==%d sum==%d count===%d res==%d\n",q.size(),sum,count,res);
		if(count>res) continue;//最多按一百次 
		if(sum==T)
		{
			res=min(res,count);
			continue;
		}
		if(sum>T) 
		{
		   if(sub)	res=min(res,sum-T+count);//按减 
			continue;
		}
		if(count!=0&&add) res=min(res,T-sum+count);//q.push(Node(T,T-sum+count));//按加 
	
		if(count==0)
		{
			for(int i=0;i<=9;i++)//按按键 
			{
				if(!vis[i]) continue   ;
		   	 	if(count+1<res) q.push(Node(sum*10+i,count+1));
			}
		}
		else if(count>0&&as)
		{
			if(count==1) count++;//printf("Yes\n"),;//第二次按,加上— 
			for(int i=0;i<=9;i++)//按按键 
			{
			if(!vis[i]) continue   ;
		   if(count+1<res) q.push(Node(sum*10+i,count+1));
			}
		}
		
		 
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(vis,false,sizeof(vis));
		for(int i=0;i<13;i++) 
		{
			int a;
			scanf("%d",&a);
			switch(i)
			{
				case 0: vis[1]=a;break;
				case 1: vis[2]=a;break;
				case 2: vis[3]=a;break;
				case 3: add=(a==1);break;
				case 4: vis[4]=a;break;
				case 5: vis[5]=a;break;
				case 6: vis[6]=a;break;
				case 7: sub=(a==1);break;
				case 8: vis[7]=a;break;
				case 9: vis[8]=a;break;
				case 10: vis[9]=a;break;
				case 11: as=(a==1);break;
				case 12: vis[0]=a;break;			
			}
		}
		scanf("%d%d",&S,&T);
//		if(sub&&as&&add) printf("0\n");
//		for(int i=0;i<10;i++) if(vis[i]) printf("%d ",i);
		res=101;
		if(T==99&&S==0&&sub)
		{
			printf("1\n");
			continue ;
		}
		if(T==0&&S==99&&add)
		{
			printf("1\n");
			continue ;
		}
		//因为台是可循环的,一定要判断两个台之间的相对距离
		if(add&&T>S)res=min(res,(int)fabs(T-S));	
		if(sub&&T>S)res=min(res,(int)fabs(S+99-T+1));	
		if(sub&&T<S)res=min(res,(int)fabs(T-S));
		if(add&&T<S)res=min(res,(int)fabs(T+99-S+1));
		bfs();
//		printf("max==%d\n",maxx);	
		if(res==101)printf("-1\n");
		else printf("%d\n",res);
		
	}
} 

/* 100 1 1 1 1 1 1 1 1 1 1 1 1 1 0 99 0 0 0 1 0 0 0 1 0 0 0 0 0 75 5 0 0 0 1 0 0 0 1 0 0 0 0 0 5 75 0 0 1 1 1 1 1 1 1 1 1 1 1 23 52 1 1 1 0 1 1 1 0 1 0 1 0 1 23 52 */




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值