zoukankan      html  css  js  c++  java
  • 【u109】数字生成游戏(gen)

    Time Limit: 1 second
    Memory Limit: 128 MB

    【问题描述】

    小明完成了这样一个数字生成游戏,对于一个不包含0的数字s来说,有以下3种生成新的数的规则:
    1. 将s的任意两位对换生成新的数字,例如143可以生成314,413,134;
    2. 将s的任意一位删除生成新的数字,例如143可以生成14,13,43
    3. 在s的相邻两位之间s[i],s[i + 1]之间插入一个数字x,x需要满足s[i]<x<s[i 1],即比它插入位置左边的数大比右边的数小。例如
    143可以生成1243,1343,但是不能生成1143,1543等。
    现在小明想知道,在这个生成法则下,从s开始,每次生成一个数,可以用然后用新生成的数生成另外一个数,不断生成直到生成t至少需要多少
    次生成操作。
    另外,小明给规则3又加了一个限制,即生成数的位数不能超过初始数s的位数。若s是143,那么1243与1343都是无法生成的;若s为1443,那么
    可以将s删除4变为143,再生成1243或1343。
    【输入文件】输入文件gen.in的第一行包含1个正整数,为初始数字s。
    第2行包含一个正整数m,为询问个数。
    接下来m行,每行一个整数t(t不包含0),表示询问从s开始不断生成数字到t最少要进行多少次操作。任两个询问独立,即上
    一个询问生成过的数到下一个询问都不存在,只剩下初始数字s。


    【输入格式】

    输出文件gen.out包括m行,每行一个正整数,对每个询问输出最少操作数,如果无论如何都不能生成t则输出-1。

    【输出格式】

    输出文件divide_b.out仅包含一个正整数,即每段和最大值最小为多少。

    【数据规模】

    对于20%的数据,s < 100;对于40%的数据,s < 1000;对于40%的数据,m < 10;对于60%的数据,s < 10000;对于100%的数据,s < 100000,m ≤ 50000。

    Sample Input1

    143
    3
    134
    133
    32
    
    
    

    Sample Output1

    1
    -1
    4
    
    
    
    

    【样例解释】

    143 -> 134 133无法得到 143 -> 13 -> 123 -> 23 -> 32 

    【题解】

    这题的输入范围不大。

    所以可以用一个1..100000的布尔型数组进行判重。

    但是对于C++选手,对字符串的操作不能单纯的用string类。

    要把数字用整形存下来。然后一个一个截出来。

    然后用乘10的方法一个一个接上去。

    然后要预处理出能到达哪些数字以及到达所需要的步骤数目,然后对于询问直接输出就可以了。

    【代码】

    #include <cstdio>
    #include <cstring>
    
    struct data //用来当做队列的数据类型 
    {
    	int step,s;	
    };
    
    int tl = 0,chushi;
    int bo[100000]; //用来判重 
    
    data team[100000]; //队列要开到10W才够用 
    
    void input_data()
    {
    	memset(bo,255,sizeof(bo)); //把bo数组一开始设置为-1 
    	scanf("%d",&chushi); //输入初始的数字 
    }
    
    void ex_change(int &a,int &b) //把字符a和字符b进行交换 
    {
    	int t;
    	t = a;
    	a = b;
    	b = t;	
    }
    
    int zhuanshuzi(int a[])//把a数组转成一个整形数字。 
    {
    	int dd = 0;
    	for (int i = 1;i<=a[0];i++) //如果是0就不乘(因为根据规则数字中是不会出现0的) 
    		if (a[i]!=0) //这一点可以利用起来。当做是去除某个数字的方法。 
    			dd=dd*10+a[i];
    	return dd;
    }
    
    void bfs() //进行广搜 
    {
    	bo[chushi] = 0;
    	int head = 0,tail = 1;
    	team[1].s = chushi;
    	team[1].step = 0;
    	while (chushi>0) //获取这个数字它的位数 这个数字有备份所以除掉没事(已经放到队列中去了) 
    		{
    			tl++;
    			chushi/=10;
    		}
    	while (head != tail) //如果头结点 不等于尾节点 
    		{
    			head++;
    			int ss = team[head].s,step0 = team[head].step,shuzi = team[head].s;
    			int l = 0 ;
    			int b[11],a[11];
    			while (ss > 0)  //把头结点的每一位都存到b数组当中去。 
    				{
    					l++;
    					b[l] = ss % 10;
    					ss = ss /10;	
    				}
    			b[0] = l; //记录下这个数字的位数 放在a[0] 
    			a[0] = l;
    			for (int i = 1;i <= l;i++) //因为那样获取是逆序的,所以再把它反过来 
    				a[i] = b[l-i+1];
    			for (int i = 1;i <= l-1;i++)
    				for (int j = i+1;j <= l;j++) //枚举所有的交换组合  
    					if (a[i]!=a[j])
    						{						
    							ex_change(a[i],a[j]); //交换这两个位置 
    							int temp = zhuanshuzi(a); //转成整形数字 
    							if (bo[temp] ==-1) //如果这个状态之前没有达到过 
    								{
    									bo[temp] = step0+1; //记录下到达它的最小步骤数。 
    									tail++; //加到尾节点上 
    									team[tail].s = temp;
    									team[tail].step = bo[temp];	
    								}
    							ex_change(a[i],a[j]);//再变回来 
    						}
    			
    			if (l > 1) //如果这个数字的长度大于1,则可以删除掉一个数字以获取一个新的数字 
    				for (int i = 1;i<=l;i++)
    					{					
    						int tt = a[i];
    						a[i] = 0; //置为0,转的时候就不会除了。 
    						int temp = zhuanshuzi(a);//把这个序列转换成一个整形数字 
    						if (bo[temp] ==-1) //没有到达过。就加到尾节点 
    							{
    								bo[temp] = step0+1;
    								tail++;
    								team[tail].s = temp;
    								team[tail].step = bo[temp];	
    							}						
    						a[i] = tt;	
    					}
    			
    			if (l < tl) //如果比原来输入的数字小。则可以再加插入一个数字。 
    				{
    					for (int i = 2;i <= l;i++)
    						{
    							for (int j = a[i-1]+1;j<=a[i]-1;j++) //可以直接根据规则枚举能插入 
    								{//哪些数字。 
    									for (int k=l+1;k>=i+1;k--)//然后要把数字都往后移 
    										a[k] = a[k-1];
    									a[i] = j;
    									a[0] = l+1;
    									int temp = zhuanshuzi(a); 
    									if (bo[temp] ==-1)
    										{
    											bo[temp] = step0+1;
    											tail++;
    											team[tail].s = temp;
    											team[tail].step = bo[temp];	
    										}	
    									a[0] = l; //回溯到之前的位数 
    									for (int k = i;k<=l;k++)//把移动的数字都撤回来 
    										a[k]=a[k+1];									
    								}
    						}
    				}
    		}
    }
    
    void output_ans() //对于每一个询问都直接输出答案就可以了。 
    {
    	int m;
    	scanf("%d",&m);
    	for (int i = 1;i <= m;i++)
    		{
    			int x;
    			scanf("%d",&x);	
    			printf("%d
    ",bo[x]);
    		}
    }
    
    int main()
    {
    	//freopen("F:\rush.txt","r",stdin);
    	input_data();
    	bfs();
    	output_ans();
    	return 0;
    }
    


  • 相关阅读:
    [Go] Slices vs Array
    [置顶] SpecDD系列:“完成” 的定义
    关于游戏开发的一点随笔
    提高效率 常用的几个xcode快捷键
    关于android 自己实现 back键 home键
    (组合数学3.1.1.1)POJ 1146 ID Codes(字典序法)
    [置顶] c# asp.net 修改webconfig文件 配置
    python数据类型和3个重要函数
    jdk环境变量配置
    VM虚拟机下在LINUX上安装ORACLE 11G单实例数据库
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632340.html
Copyright © 2011-2022 走看看