CSDN论坛上的一道算法题

源地址为:http://bbs.csdn.net/topics/390854089

昨天晚上在CSDN论坛上看到这道题,思索一番后想到一个解决方案,也简单实现了。今天早上把博客补一补。算是做个笔记吧。

题目:

有m个人面向南方站成一排(m ≥1),每喊一次口号可以有n个人同时转身一次(1≤n≤m),问共需喊多少次口号所有人最终全部面向北方?
请编写一个函数,函数有两个参数,分别为m和n,函数返回值为最终需要的次数,若经过无穷大次仍然无法全部转向北方,则输出-1.
例1:
m = 6,n =5:
用0表示面向南方,1表示面向北方,如下:

0 0 0 0 0 0
0 1 1 1 1 1
1 1 0 0 0 0
0 0 0 1 1 1
1 1 1 1 0 0
0 0 0 0 0 1
1 1 1 1 1 1
返回6
例2:
m = 3,n = 2:
返回-1

关注这个帖子的人还蛮多的,不少人都或完整或不完整的给出了自己的方案。这些方案集中在寻找这个问题的公式解。

在还没看下面的回答之前,我思考了一下,与大部分网友不同的是,从一开始我就没想到找到这个问题的公式解(每个人想法不一样)。我发现本质上是一个搜索问题。为什么这么说,且看下面的分析。

1.这m个数其实没有位置之分,m的数的状态可以用0和1的个数来标记。

2.一旦指定m,m就不会再变化了,所以甚至可以只用0的个数来标记状态,在这里我用所有m个数的和来标记状态(1的个数)。

3.每一次变化n个数,相当于向前搜索。用x表示0的个数,用y表示1的个数。变化n个数对m个数和的影响就是加上一个数。这个数可能有多种可能,取值的上限和0的个数有关,下限和y的个数有关。用max和min来表示上限和下限,具体来说,当x>=n时,max = n;当x<n时,max = x - (n - x) = 2x - n;当y>=n时,min = -n;当y< n 时,min = n - 2y。

4.人工智能课上介绍的搜索算法有很多,BFS,DFS,A-star之类的。BFS能够得到最优解,但是时间、空间开销可能比较大,DFS可能在短时间内找到解,但不能保证是最优的,A-star有很多优点,解是最优的,速度也快,可是需要启发式函数。这里我采用BFS。

下面是我的代码:

import java.util.ArrayList;
import java.util.Iterator;

import javax.management.openmbean.ArrayType;
import javax.management.openmbean.SimpleType;

public class OneAlgorithm {

	/**
	 * 
	 * @param x: x is number of zeros
	 * @param y: y is number of ones 
	 * @return
	 */
	public static int max(int x, int y, int n){
		int max = 0;
		if(x >= n)
			max = n;
		else
			max = 2 *x - n;
		
		return max;
	}
	
	public static int min(int x, int y, int n){
		int min = 0;
		if(y >= n)
			min = -n;
		else
			min = n - 2*y;
		
		return min;
	}
	
	/**
	 * 
	 * @param m
	 * @param n
	 * @return
	 */
	public static int BFS(int m, int n){
		if(m % n == 0)
			return n;
		
		ArrayList<Integer> states = new ArrayList<Integer>();
		ArrayList<Integer> floors = new ArrayList<Integer>();
		int floor = 0;
		int zeros = m;
		floors.add(floor);
		states.add(zeros);
		
		int index = 0;
		
		int max, min;
		int x = m;
		int y = 0;
		max = max(x,y,n);
		min = min(x,y,n);
		
		while(true){
			while(max >= min)
			{
				zeros = x - min;
				if(zeros == 0)
					return floors.get(index)+1;
				if(floors.indexOf(index) == floor)
					floor++;
				if(!states.contains(x-min))
				{
					states.add(x-min);
					floors.add(floor);	
				}
				min = min + 2;
			}	
			index = index + 1;
			if(index+1 > states.size())
				return -1;
			x = states.get(index);
			y = m - x;
			max = max(x,y,n);
			min = min(x,y,n);
		}
	}
	
	public static void main(String[] args){
		int temp = BFS(13,7);
		System.out.println(temp);
	}
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值