基本思想(模拟)——鸡兔同笼+校门外的树+约瑟夫问题+装箱子问题+排列【POJ 1833】

用模拟法解决问题的基本思想是对事物进行抽象,将现实世界的事物映射成计算机所能识别的代码符号,将现实事物之间的关系映射成运算或逻辑控制流。

目录

鸡兔同笼

校门外的树 

约瑟夫问题 

装箱子问题 

 排列问题


模拟法对于程序设计来说,就类似十位数的加减乘除对于数学运算,又比如学习语言时的拼音和字母。我们通过模拟以及更进一步的抽象,可以建立起连接现实世界和计算机的代码世界的桥梁。

(1)习惯模拟的思考方式,学会对事物进行抽象的处理,将动态的流程映射为抽象的代码

(2)养成良好的代码编写风格和编程习惯。

(3)熟悉最基本的程序结构,对我们来说,这是后续学习的基础和基本功,对程序来说,是复杂程序的基本单元。

难度依次递减:鸡兔同笼——>校门外的树——>约瑟夫问题——>装箱子问题——》排列【POJ 1833】

鸡兔同笼

今有兽,六首四足;禽,四首二足,下有四十六足。问:至多几只?至少?

N位脚数,用模拟法将问题抽象出为脚数是奇数还是偶数、能否被4整除

难度:♥

(1)、若N是奇数,则说明没有满足条件的答案

(2)、若N是偶数且能被4整除,则最少有N/4只兔子,最多N/2只鸡

(3)、若N是偶数且不能被4整除,则最少有N/4只兔子和一只鸡,最多有N/2只鸡

package com.suanfa;

import java.util.Scanner;

public class ChickAndRabbit
{
    public static void main(String[] args)
    {
        Scanner scn = new Scanner(System.in); //从外设接受数据
        System.out.println("输入你要测试鸡兔同笼问题的组数:");
        int n = scn.nextInt();
        for (int i = 0; i < n; i++)
        {
            System.out.print("输入你第"+ (i + 1) +"次看到的脚数量:");
            int x = scn.nextInt();
            if (x < 0)
                System.out.println("输入的值错误");
            else if (x % 4 == 0)
                System.out.println("最多" + x / 2 + "  最少" + x / 4);
            else if (x % 2 == 0)
                System.out.println("最多" + x / 2 + "  最少" + (x / 4 + 1));
            else
                System.out.println("/0.-.0\\");
        }
    }
}

校门外的树 

校门外的树:校门外长度为L的树的马路有一排树,每两棵相邻的树之间的间隔是1m,在路间修高铁,需要移走一些树,问题为完成修高铁后马路上还有多少树。

难度:♥♥

方法一:将树抽象出来为一个数组,每当树被砍掉就令数组对应位置的值变化,没被砍就为非0,砍了就为1。

方法二:暂无

方法三:暂无

package com.suanfa;

import java.util.Scanner;

public class SchoolTrees
{
    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);
        int l=sc.nextInt();
        int m=sc.nextInt();
        int[] s=new int[l+1];

        for(int i=0;i<=l;i++)
            s[i]=0;

        for(int i=0;i<m;i++)
        {
            int a = sc.nextInt();
            int b = sc.nextInt();
            for(int j=a;j<=b;j++)
                s[j]++;
        }

        int sum=0;
        for(int i=0;i<=l;i++)
            if(s[i]==0)
            {
                sum++;
            }
        System.out.println(sum);
    }
}

约瑟夫问题 

约瑟夫问题(猴子选大王):约瑟夫问题也叫做约瑟夫环,是一个数学应用问题。

问题内容:已知有n个人(分别编号为1,2,3…n)围坐成一圈,从第一个人开始报数,报到数m的人出圈;再从下一个人开始重新报数,报到m的人出圈;直至剩下最后一个人的时候游戏结束。输出剩下的人的原始编号。

难度:♥♥

解题思路:这个题通过数学推导找到一个合适的解是十分困难的,因此用算法的思想来解决,用基本的思想就是模拟整个过程。将N个树排成一圈,从1开始数,然后数到对应的M就划掉,一直循坏下去,直到最后就只剩下一个数。

package com.suanfa;
import java.util.Arrays;
import java.util.Scanner;
public class Yuesefu
{
    public static void main(String[] args)
    {
        Scanner sca = new Scanner(System.in);

        System.out.println("输入猴子数量");
        int n = sca.nextInt();

        System.out.println("输入数到数字退圈的数字");
        int m = sca.nextInt();

        int[] a = new int[n];  //声明一个数组

        Arrays.fill(a,0);   //数组赋值为0
        int count = 0;   //记录退出去的人数
        int s=0;    //纪记录从0数到m
        
        //退出的人数小于总人数继续进行,就算第一轮结束,只要人数不满足就继续第二轮循坏
        while (count < n)
        {
            for (int i = 0; i < a.length; i++) //循坏判断
            {
                if (a[i] == 0)  //当值为0就令s加一
                {
                    s++;
                    if (s == m) //s等于m  则退出一个人,并使这个人赋值为1
                    {
                        a[i] = 1;
                        count++;  //退出一个就加一个
                        s = 0;  //刷新s的值,开始下一轮计数
                    }
                }
                if (count == n - 1) //当退出的人等于n-1停止循坏
                    break;
            }

        }
        //遍历输出值为0的位置
        for (int i=0; i<a.length; i++)
        {
            if(a[i] == 0)
                System.out.println("\n剩下的是"+(i+1));
        }
    }
}

装箱子问题 

装箱子问题:有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30),每个物品有一个体积(正整数)。要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。

第一行为一个整数,表示箱子容量;第二行为一个整数,表示有n个物品;接下来n行,每行一个整数表示这n个物品的各自体积。

难度:♥♥♥♥

这个题,我刚拿到的时候看起来感觉很繁琐,不过带入一些数据理解这个分析过程还是很好理解的。

一个6X6的产品,装入一个6X6的箱子中就只剩0X0的空间^-^

一个5X5的产品,装入一个6X6的箱子中还有11个1X1的空间

一个4X4的产品,装入一个6X6的箱子中还剩5个2X2的空间

一个3X3的产品,装入一个6X6的箱子中还剩7个1X1的空间+5个2X2的空间

两个3X3的产品,装入一个6X6的箱子中还剩6个1X1的空间+3个2X2的空间

 

 

三个3X3的产品,装入一个6X6的箱子中还剩5个1X1的空间+1个2X2的空间

四个3X3的产品,装入一个6X6的箱子中还剩0个1X1的空间+0个2X2的空间

package com.suanfa;

import java.util.Scanner;

public class Box
{
    public static void main(String[] args)
    {
        int n, a, b, c, d, e, f, y, x;//定义需要的变量
        Scanner sca = new Scanner(System.in);
        System.out.println("输入1x1的产品数:");
        a = sca.nextInt();
        System.out.println("输入2x2的产品数:");
        b = sca.nextInt();
        System.out.println("输入3x3的产品数:");
        c = sca.nextInt();
        System.out.println("输入4x4的产品数:");
        d = sca.nextInt();
        System.out.println("输入5x5的产品数:");
        e = sca.nextInt();
        System.out.println("输入6x6的产品数:");
        f = sca.nextInt();
        int[] u = {0, 5, 3, 1};//将两个箱子
        n = f + e + d + (c + 3) / 4;
        x = 5 * d + u[c % 4];

        if (b > x)
            n += (b - x + 8) / 9;

        y = 36 * n - 36 * f - 25 * e - 16 * d - 9 * c - 4 * d;

        if (a > y)
            n += (a - y + 35) / 36;

        System.out.println(n);
        }
}

 排列问题

问题描述:给出一个正整数n,则从1~n这n个数可以构成N!个排列,将这些排列按照从小到大的顺序列出,例,n=3时,排列有123,132,213,231,312,321这六种排列。

任务描述:给出某个排列,求这个排列下的k个排列,若遇到最后一个排列,则下一个是第一个排列,即使1 2 …… n。例如,n=3,k=2,给出排列321,下两个是132。

假如一组数,2341546.

2341546        k=0

2341564        k=1

2341645        k=2

2341654        k=3

2344156        k=4

2344165        k=5

…………        ……

2346541        k=n

…………        ……

2314456        k=m

…………        ……

6544321        k=...

从上面的规律可知,从后面往前推,将后面的进行升序排列

1、从右往左找,找到某个位置i,满足i-1的位置的数比i位置的数小

2、将i-1位置的数,与右边所有的数对比,将比他大的中最小的数进行交换

(比i大的最小的数:4比3大,5比三大,6也比三大,但是4是比三大中最小的一个数)

3、将i~n之间的数进行升序排列

package com.suanfa;

import java.util.Arrays;

import java.util.Scanner;

public class PailieTwo
{
    public static void main(String[] args)
    {
        Scanner scan = new Scanner(System.in);
        System.out.println("输入数组大小");
        int  n = scan.nextInt();
        int[] arr = Sha(n);
        System.out.println(Arrays.toString(arr));
        System.out.println("第几个排列");
        int k = scan.nextInt();
        for (int i = 0; i < k; i++)
            System.out.println("排列下"+(i+1)+"排列是"+ Arrays.toString(next(arr)));
    }

    private static int[] next(int[] arr)
    {
        int size = arr.length;
        int flag = size - 1;
        int tmp;

        while (flag != 0 && arr[flag - 1]>arr[flag])
            flag--;

        if (flag == 0) {
            for (int i = 0; i < size / 2; i++) {
                tmp = arr[i];
                arr[i] = arr[size - 1 - i];
                arr[size - 1 - i] = tmp;
            }
            return arr;
        }

        for (int i = size - 1; i >= flag; i--) {
            if (arr[i] > arr[flag - 1]) {
                tmp = arr[i];
                arr[i] = arr[flag - 1];
                arr[flag - 1] = tmp;
                break;
            }
        }

        while (flag < size -1)
        {
            tmp = arr[flag];
            arr[flag] = arr[size - 1];
            arr[size - 1] = tmp;
            flag++;
            size--;
        }
        return arr;
    }

    private static int[] Sha(int n)//进行随机一个组合
    {
        int[] baseA = new int[n];//弄一个数组存储
        for (int i = 0; i < n; i++)//将1~n的值赋入数组
            baseA[i] = i + 1;
        int[] tarA = new int[n];//接受打乱后的数组
        int index;//记录下标
        for (int i = 0; i < n; i++)
        do {
            index = (int) (Math.random() * n);//随机值从0~n-1
            tarA[i] = baseA[index];//将随机到的值对应的值传入新数组
            baseA[index] = -1;//将随机到的值为-1,下面进行判断,如果值是-1就跳过,进入下一个值
        } while (tarA[i] == -1);
        return tarA;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lungcen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值