翻硬币游戏的解

本文介绍了一个编程问题,给定一个初始硬币状态和目标状态,目标是找出通过每次翻转相邻两个硬币所需的最小步骤数。文章讨论了多种解决方案,包括遍历、条件判断和优化算法的应用。
摘要由CSDN通过智能技术生成

题目背景

小明正在玩一个“翻硬币”的游戏。

题目描述

桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零),比如可能情形是 **oo***oooo,如果同时翻转左边的两个硬币,则变为 oooo***oooo。现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?

输入格式

两行等长字符串,分别表示初始状态和要达到的目标状态,每行长度小于 10001000。

数据保证一定存在至少一种方案可以从初始状态和要达到的目标状态。

输出格式

一个整数,表示最小操作步数。

输入输出样例

输入 #1复制

**********
o****o****

输出 #1复制

5

输入 #2复制

*o**o***o***
*o***o**o***

输出 #2复制

1

需要明确的一个事实就是只用按顺序遍历,并且左右都一样(只和最远的两个不同点所在的区间有关)。至于具体原因则在最后的解法的解读里面。

import java.util.Scanner;

public class Main {
	public static void main(String args[]) {
		String x,y;
		int num = 0;
		char a[] = new char[1000];
		char b[] = new char[1000];
		try (Scanner sc = new Scanner(System.in)) {
			x = sc.nextLine();
			y = sc.nextLine();
		}
		for(int i =0; i<x.length();i++) {
			a[i] = x.charAt(i);
			b[i] = y.charAt(i);
		}
		for(int i =0; i<x.length();i++) {
			if(a[i] == b[i]) {
				continue;
			}else {
				a[i+1] =(a[i+1]=='*' ?'o':'*') ;
				num++;
			}
		}
		System.out.println(num);
}
}

在这个代码里面


				a[i+1] =(a[i+1]=='*' ?'o':'*') ;

整一个被依据条件赋予了'o'或者'?'。并且要比下面这个情况(我写的)好多了:

package 练习; import java.util.; public class 第一次 
{ public static void main(String[] args) {
 Scanner scan = new Scanner(System.in); 
StringBuilder str1 = new StringBuilder();
 StringBuilder str2 = new StringBuilder(); 
int m; for(int i = 1 ; i <= 1000; i++) {
 if(str1.charAt(i) != str2.charAt(i)) {
   if(str1.charAt(i) = '') str1.insert(i,'o');
   else 
       str1.insert(i,'*');
   	  if(i < 1000 && str1.charAt(i + 1) == '*')
		     str1.insert(i,'o');
		  else
			  str1.insert(i,'*');
	  m++;
	  i++;
	  
   }
  } 
 } 
} 

一句顶我好几句。

由此可见这种根据条件选择的非此即彼的判断选择要用a > b ? x:y;这样的三元语句。

看了别人的解法:

  • 由于不会有无解的情况,我们可以从左至右依次循环遍历 字符串的每一个字符,判断是不是与 串相应的字符相等。
  • 若不相等,翻转这枚和下一枚(他右边的)硬币。
  • 这里可以偷个懒,由于之后不会再用到这枚硬币,可以不翻,只翻下一枚。
    #include<bits/stdc++.h>
    using namespace std;
     
    char a[1005];
    char b[1005];
     
    int main(){
        cin>>a>>b;
        int len=strlen(a);
        int i=0,sum=0;
        while(i<len){
            if(a[i]!=b[i]){
            	a[i+1]=(a[i+1]=='*'?'o':'*');
                sum++;
            }
            i++;
        }
        cout<<sum;
        return 0;
    }

    这样计算的量级减少了几个N(不看大的O(N),看具体的细节) 

还有一种方法,虽然没有优化但是可以看看不同的角度下的人是如何理解这一个题目的:

#include<bits/stdc++.h>
using namespace std;
string a, b;
int ans, bg = -1, n;
int main(){
	cin >> a >> b;
	n = a.length();
	for(int i = 0; i < n; i++){
		if(a[i] != b[i]){
			if(bg == -1){//找第一个不同的硬币
				bg = i;
			}else{ 
				ans += (i - bg);//找到第二个不同的硬币
				bg = -1;//接着找下一个不同段 
			}
		}
	}
	cout << ans;
	return 0; 
}

这里其实就是运用了基本结构构建思想(就是欧拉解决戈尼斯堡七座桥难题的那个思想)**对oo、

*******对o*******o 、*****对o***o 、n 个*对o(这里n个'*')o结构其实都一样,而所有的硬币排序都可以被拆成这这样的结构,而这样的结构翻成对应的状态所需要的次数有规律(整个小结构字符数量减去1就是翻转次数),所以可以。

下面只是个人胡思乱想的爱好


  另外,应当明确的一个事实就是我们写算法就是为了让计算机的for循环结构和while结构帮我们自动处理同一的大量的执行。还有一点就是它们必须都是满足某种规律的,然而有的题目就比如翻硬币是没有规律的(我指的是明显的使得程序直接按照最朴素的想法直接进行的),这时for和while(虽然不一定但依然是在for和while的基础上进行转化的)肯定还是要用到的。所以我们只能按部就班的直接翻硬币。这时往往是要从另外一个角度来看待这一个问题的。我们可以毫不怀疑的说就是这个直接从开头开始翻转了。因为像数学一样转化这个问题就说明它是有规律的,但是请注意到那些看可以被重写(重述)的问题是在基本的问题上进行改进的(因为这就和数学里面的“范畴论”一样,不同的问题之间之所以可以一步一步的转化就是因为它转化后的,如代数转几何是因为几何就是代数建立的基础)而算法的简化问题就是在之前的问题的认识之下(不是穷举)一一对应的结果(即使人们并未意识到),所以我们可以丝毫不怀疑的说就是要这样解决的。

  但是用已有的去重构那些复杂的是很累的,所以数学中才会用那些高级的理论来解决成了那些基础数学很难解决的问题(高级理论放大了基础的一些特性,更高又在更高级的上面构造,(高级又有“自己的”特点,又可以深挖))。对应到同样是逻辑为基础的计算机里就是——高级算法和数据结构了。这样子我们就看清楚了哪些问题是值得我们去用算法和数据结构的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值