Java趣味编程(一)

1_1

问题描述:根据福利彩票的规则,6个蓝色球,范围1--32,不允许重复,1个红色球,范围1-16,自动生存6个蓝色球,1个红色球。

 

import java.util.Arrays;   

import java.util.Random;   

import java.util.Scanner;

public class Ch11_2

{   

    /**  

     * 根据给定的最小数字和最大数字,以及随机数的个数,产生指定的不重复的数组  

     * @param begin 最小数字(包含该数)  

     * @param end 最大数字(不包含该数)  

     * @param size 指定产生随机数的个数  

     *

     * 实现思路:首先定义一个方法,使它能够产生6个不重复的蓝色随机数,存放到数组中,

     * 再产生1个红色随机数,最后他们组合在一起就是题目所求

     */  

    public static int[] generateRandomNumber(int begin, int end, int size)

    {   

        // 加入逻辑判断,确保begin<end并且size不能大于该表示范围   

        if (begin >= end || (end - begin) < size)

        {   

            return null;   

        }          

        // 种子你可以随意生成,但不能重复   里面存放的是你的取值范围

        //本题就是 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]

        int[] seed = new int[end - begin];    

      

        for (int i = begin; i < end; i ++)

        {   

            seed[i - begin] = i;   

        }   

        int[] ranArr = new int[size];   

        Random ran = new Random();   

        // 数量你可以自己定义。  这里生成了6个蓝色球的号码

        for (int i = 0; i < size; i++)

        {   

            // 得到一个位置   

            int j = ran.nextInt(seed.length - i);              

            // 得到那个位置的数值

            ranArr[i] = seed[j];   

            // 将最后一个未用的数字放到这里 ,这样就把取出的数覆盖了,达到了不重复的目的。  

            seed[j] = seed[seed.length - 1 - i];   

        }   

        return ranArr;   

    }   

  

    public static void main(String[] args)

    {

    int[] ranArr={};

    int red;

    Scanner input=new Scanner(System.in);

    Random ran = new Random();

    

    System.out.println("欢迎使用双色球自动摇号系统");

    System.out.print("确实摇号(y/n)?");

    String go;

    go=input.next();

    

    while(go.equalsIgnoreCase("y"))

    {

     ranArr= generateRandomNumber(1,33,6);

     red=ran.nextInt(16);

     System.out.println(Arrays.toString(ranArr)+" "+red);   

     System.out.print("继续摇号(y/n)?");

     go=input.next();

    }

        System.out.println("谢谢使用!");   

    }   

  

}   

 

 

 

1_2 超长整数的相加

问题描述:编写程序,实现超过整形变量存储范围数据的相加

 

import java.util.Arrays;

import java.util.Scanner;

public class Ch11_4

{

/**

 * 实现思路:将两个超长的整形转换为字符串   

 * 2 将两个字符串变为等长,如:30812111123 298----30812111123  00000000289

 * 3 将两个字符串对应相加,结果存到到另一个字符串

 * 4 最后对新的字符串做进位处理

 * @param args

 */

public static void main(String[] args)

{

        

//Scanner input=new Scanner(System.in);

//System.out.print("请输入第一个加数:");

//String addA=input.next();

//System.out.print("请输入第二个加数:");

//String addB=input.next();

String addA="30812111123";

        String addB="298";

        //调用方法计算结果,输出

        System.out.println(addA+"+"+addB+"="+strvalue(addA,addB));

    }

   /**

   *将两个字符串相加,得到新的字符串

    */

    public static String strvalue(String addA,String addB)

    {

        String strvalue="";

        int lenA=addA.length();

        int lenB=addB.length();

 

        int templen=0;

        //调整长度相同

        if(lenA>=lenB)

        {

            templen=lenA-lenB;

            addB=maxlen(addB,templen);//调整长度,使其跟大数长度一致

        }else{

            templen=lenB-lenA;

            addA=maxlen(addA,templen);

        }

        char addcharA[]=addA.toCharArray();

        char addcharB[]=addB.toCharArray();

 

        int len=addcharA.length;

        int valueC[]=new int[len];

        for(int i=0;i<len;i++)

        {

            //取出字符串中的数转换为数字

        int a=Integer.parseInt(String.valueOf(addcharA[i]));

            int b=Integer.parseInt(String.valueOf(addcharB[i]));

            valueC[i]=a+b;//每项相加存储

        }

        System.out.println(Arrays.toString(valueC));

        int tmp=0;//代表进位

        //处理进位  从个位开始

        for(int i=valueC.length-1;i>=0;i--)

        {

            if(valueC[i]>=10)

            {

                strvalue=String.valueOf(valueC[i]+tmp-10)+strvalue;

                tmp=valueC[i]/10;

            }else{

                strvalue=String.valueOf(valueC[i]+tmp)+strvalue;

                tmp=0;

            }

        }

        return strvalue;

    }

    

    //调整长度,使其长度一样

    private static String maxlen(String str,int templen)

    {

        String strmax=null;

        StringBuffer buff=new StringBuffer();

        for(int i=0;i<templen;i++)

        {

            buff.append("0");

        }

        strmax=buff.toString()+str;

        return strmax;

    }

}

 

 

1_3 尾数前移

问题描述:求一个自然数N,个位数是6,6提到最前面得到的数是N4

 

 

public class Ch11_5

{

/**

 * 问题分析:假设这个数是n6(n是从1开始的正整数)

 * 2 满足关系  6n=4*(n6)

 * 3 n6=n * 10 + 6;  6n=6 * Math.pow(10,i) + n;  i代表的是6处在的是十位还是百位等等  (十位 i=1....)

 * @param args

 */

public static void main(String[] args)

{

int n = 0;//代表6的前面部分,“n6”

int N;//6移动前,即N=n6

int M;//6移动到数字首部后,即M=6n

int buf;

int i = 0;//代表数字的长度

while(true)//穷举

{

//移动前

N = n * 10 + 6;

    buf = n;

    //计算数字的长度,确定6移到首部的权重,即:6代表的是十位还是百位等等

    while(buf!=0)

    {

    i++;

        buf = buf/10;

    }

    //移动后

    M = (int)(6 * Math.pow(10,i)) + n;

    //条件满足,输出,退出循环

    if(M == (4*N))

    {

    System.out.print("要找的数为:"+N);

        break;

    }

    n++;//穷举变量修改

    i = 0;//长度值复位

}

}

}

 

 

1_4国际象棋有八行八列,64个单元格,在棋盘上摆放八个皇后,使其不能相互攻击,就是说任意两个皇后不能处在同一行,同一列或同一斜线上,问一共有多少中摆法

 

import java.util.Arrays;

 

 

public class Ch11_6

{

static int result=0;

static int[] WeiZhi=new int[8];//全局数组,下标代表行,里面的元素代表列(就是我们上算法分析的解向量)

static void EightQueen(int n)// 算法

{

   int i,j;

   int ct;//用于判断是否冲突,1代表不冲突

   if (n == 8)//8个皇后已放置完成

   {

   System.out.println(Arrays.toString(WeiZhi));

   result++;

  return;

   }

   for (i = 1; i <= 8; i++)//试探

   {

  WeiZhi[n] = i;//在该列的第i行上放置

  //断第n个皇后是否与前面皇后形成攻击

  ct=1;

  for (j = 0; j < n; j++)

  {

  if (WeiZhi[j] == WeiZhi[n])// 形成攻击

  {

  ct=0;

  }

  else if (Math.abs(WeiZhi[j] - WeiZhi[n]) == (n - j))// 形成攻击

  {

  ct=0;

  }

  else

  {

  }

  }

 

  if (ct==1)//没有冲突,就开始下一列的试探

 EightQueen(n + 1); //递归调用

   }

}

 

public static void main(String[] args)

{

   EightQueen(0);//求解

   System.out.println("一共有"+result+"种解法");

}

}

 

 

1_5  评委计分问题

问题描述:有10个评委为参赛选手打分,分数是1100。选手最后的得分是:去掉一个最高分,去掉一个最低分,其余8个评委取平均值。

import java.util.Scanner;

 

public class Ch11_7

{

public static void main(String[] args)

{

Scanner in=new Scanner(System.in);

int num,i,max,min,sum,avg;

max=0; /*先假设当前的最大值max0*/

min=100; /*先假设当前的最小值min100*/

sum=0; /*将求累加和变量的初值置为0*/

for(i=1;i<=10;i++)

{

System.out.print("请第"+i+"评委输入分数: ");

num=in.nextInt(); /*输入评委的评分*/

sum+=num; /*计算总分*/

if(num>max)max=num; /*通过比较筛选出其中的最高分*/

if(num<min)min=num; /*通过比较筛选出其中的最低分*/

}

System.out.printf("去掉一个最高分:%d \n去掉一个最低分:%d ",max,min);

avg=(sum-max-min)/8;

System.out.printf("\n平均得分:%d ",avg); /*输出结果*/

}

 

}

 

1_6 罗马数字

将阿拉伯数字(01000)转换为罗马数字,对应关系如下表

1

2

3

4

5

6

7

8

9

10

20

30

40

50

60

70

80

90

X

XX

XXX

XL

L

LX

LXX

LXXX

XC

100

200

300

400

500

600

700

800

900

C

CC

CCC

CD

D

DC

DCC

DCCC

CM

 import java.util.Scanner;

 

public class Ch11_8

{

//建立对照表

static String a[][]={{"","I","II","III","IV","V","VI","VII","VIII","IX"},

        {"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"},

        {"","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"}};

public static void main(String args[])

{

Scanner in=new Scanner(System.in);

System.out.print("请输入一个阿拉伯数字:");

int n=in.nextInt();

int t=0;

System.out.printf("%d=",n);

int i=1000;

int fz;//分子

int fm;//分母

int row;

int col;

for(int m=0;m<3;m++)

{

fz=n%i;//只取1000以下的数

fm=i/10;

t=fz/fm;//从高位向低位依次取出各位数字

row=2-m;

col=t;

System.out.printf("%s",a[row][col]+"\t");//对照表翻译输出

i=i/10;

}

System.out.printf("\n");

}

}

 

 

1_7 找假币问题

问题描述:现在有n枚硬币,其中一枚是假币,外观无法辩出。只知道假币比真币稍轻。要求仅仅使用一个天平,如何用最少的步骤找到假币?

该问题和二分法类似,可以用分治法解决。

 

import java.util.Scanner;

 

 

public class Ch11_9

{

static final int MAXNUM=30;

static int FalseCoin(int coin[],int low,int high)//算法

{

    int i,sum1,sum2;

int re=0;

sum1=sum2=0;

    if(low+1==high)//仅剩下两个硬币

    {

        if(coin[low]<coin[high]) //左边轻

{

re=low+1;//下标从0开始,加1

return re;

}

        else 

{

re=high+1;

return re;

}

    }

    if((high-low+1)%2 == 0)//n是偶数

    {

        for(i=low;i<=low+(high-low)/2;i++)

{

            sum1= sum1 + coin[i];       //前半段和

}

        for(i=low+(high-low)/2+1;i<=high;i++)

{

            sum2 = sum2 + coin[i];       //后半段和

}

        if(sum1>sum2) //前半段重,假币在后半段

{

re=FalseCoin(coin,low+(high-low)/2+1,high);//递归,在后半段中查询

return re;

}

        else if(sum1<sum2)//后半段重,假币在前半段

{

re=FalseCoin(coin,low,low+(high-low)/2);//递归,在前半段中查询

return re;

}

else

{

}

    }

    else   //n是奇数

    {

        for(i=low;i<=low+(high-low)/2-1;i++)

{

            sum1= sum1 + coin[i];       //前半段和

}

        for(i=low+(high-low)/2+1;i<=high;i++)

{

            sum2 = sum2 + coin[i];       //后半段和

}

        

        if(sum1>sum2)   //前半段重,假币在后半段

{

re=FalseCoin(coin,low+(high-low)/2+1,high);//递归,在后半段中查询

            return re;

}

        else if(sum1<sum2)//后半段重,假币在前半段

{

re=FalseCoin(coin,low,low+(high-low)/2-1);//递归,在前半段中查询

            return re;

}

else//前后一样重,假币在中间

{

re=low+(high-low)/2+1;//计算中间位置

return re;

}

    }

return re;

}

public static void main(String[] args)

{

int[] coin=new int[MAXNUM];

int i,n;

int weizhi;

    System.out.println("分治算法求解假银币问题!");

System.out.print("请输入银币总的个数:");

Scanner input=new Scanner(System.in);

n=input.nextInt();//银币总的个数

System.out.print("请输入银币的真假:1代表假币,2代表真币");

for(i=0;i<n;i++)

{

coin[i]=input.nextInt();//输入银币的真假,1代表假币,2代表真币

}

weizhi=FalseCoin(coin,0,n-1);//调用求假币方法,求解

    System.out.println("在上述"+n+"个银币中,第"+weizhi+"个银币是假的!");

}

}

 

 

1_8 窃贼问题(0-1背包问题)

问题描述:有一个窃贼带着一个背包去偷东西,房间里有5件物品,其重量和价值如下:

物品一:公斤  48 

物品二:公斤  40 

物品三:公斤  12 

物品四:公斤  

物品五:公斤  

窃贼希望拿到更大价值的东西,但是他的背包容量是8公斤,那么窃贼应该装上哪些东西才能达到要求?

 

分析:这是一类典型的0-1背包问题下面我将提供两种解法:回溯法和动态规划法

 

动态规划法解决0-1背包问题

动态规划法的核心就是递归方程。如果你不能推出递归方程,那你就老老实实用回溯法吧

m(i, j)是背包容量为j,可选物品为0,1,...,i0-1背包问题的最优值。

m(i, j) = 0j=0

m(i, j) = 0i=0 && j < wi

m(i, j) = vii=0 && j >= wi

m(i, j) = m(i-1, j)j < wi

m(i, j) = max{m(i-1, j), m(i-1, j-wi) + vi}j >= wi

 

 

public class Ch11_10

{

//背包容量

private int c;

//物品重量数组

private int[] w;

//物品价值数组

private int[] v;

private int[][] m;//m(i, j)是背包容量为j,可选物品为0,1,...,i0-1背包问题的最优值。

//记录结果

private int[] x;

//最大价值

private int maxV;

 

//构造方法,数据初始化

public Ch11_10(int[] w, int[] v, int c)

{

this.w = w;

this.v = v;

this.c = c;

m = new int[w.length][c+1];

x = new int[w.length];

}

 

/** 0-1背包问题  动态规划求解

 *递归式

 *  m(i, j) = 0j=0

 *  m(i, j) = 0i=0 && j < wi

 *  m(i, j) = vii=0 && j >= wi

 *  m(i, j) = m(i-1, j)j < wi

 *  m(i, j) = max{m(i-1, j), m(i-1, j-wi) + vi}j >= wi

 */

public void knapsack()

{

//初始化

for (int i = 0; i < m.length; i++)

{

m[i][0] = 0;

}

for (int j = 0; j < m[0].length; j++)

{

if (w[0] <= j)

{

m[0][j] = v[0];

}

else

{

m[0][j] = 0;

}

}

for (int i = 1; i < m.length; i++)

{

for (int j = 1; j < m[i].length; j++)

{

if (j < w[i])

{

m[i][j] = m[i-1][j];

}

else

{

m[i][j] = Math.max(m[i-1][j], m[i-1][j-w[i]] + v[i]);

}

}

}

maxV = m[m.length - 1][c];

System.out.println("最大值为:"+maxV );

}

 

//得到最优解

public int[] getResult()

{

int tmp = c;

int i;

for (i = m.length - 1; i > 0; i--)

{

//根据二维数组最后一列,相邻两行是否相等,如果相等,没有加入,否则,加入

if (m[i][tmp] == m[i-1][tmp])

{

x[i] = 0;

}

else

{

x[i] = 1;

tmp = tmp - w[i];

}

}

x[i] = (m[0][c] != 0) ? 1 : 0; //第一行,单独处理,如果非零,即加入

return x;

}

 

//打印数组m

public void printM()

{

for (int i = 0; i < m.length; i++)

{

for (int j = 0; j < m[i].length; j++)

{

System.out.printf("%2d  ",m[i][j]);

}

System.out.println();

}

}

 

public static void main(String[] args)

{

int[] w = {6, 5, 2, 1, 1};//物品重量

int[] v = {48, 40, 12, 8, 7};//物品价格

int c=8; //背包容量

Ch11_10 k = new Ch11_10(w, v, c);//初始化数据

k.knapsack();//调用背包方法,填充动态规划表

int[] x = k.getResult();//得到最优解

System.out.println("具体组合情况如下(1代表选中,0代表未选):");

for (int i = 0; i < x.length; i++)

{

System.out.print(x[i] + " ");

}

System.out.println("\n动态规划表如下:");

k.printM();//打印动态规划表

}

}

 

 

1_9  回溯法解决0-1背包问题

package chapter11;

 

import java.util.Arrays;

 

public class Ch11_11 {

//背包容量

private int c;

//物品重量数组

private int[] w;

//物品价值数组

private int[] v;

//记录结果

private int[] x;

//记录最优解

private int[] jie;

//记录背包所装物品的最大值

private int maxValue;

public Ch11_11(int[] w, int[] v, int c){

this.w = w;

this.v = v;

this.c = c;

x = new int[w.length];

jie=new int[w.length];

}

public void DP(int n){

if(n==w.length){

if(heFa(x)){

printJie(x);

}

}else{

for(int i=0;i<2;i++){

x[n]=i;

DP(n+1);

}

}

}

/**

 * 判断当前的结果x是不是合法的

 * 所装物品的重量和超过背包容量就非法

 * @param x2

 * @return 真还是假

 */

private boolean heFa(int[] x2) {

int result=0;

for(int i=0;i<x2.length;i++){

if(x[i]==1)

result+=w[i];

}

if(result>c)

return false;

else

return true;

}

/**

 * 打印出符合条件的所有解

 * 并且将最大值存到maxValue,将最大值的数组存放到jie

 * @param x2

 * @return

 */

private void printJie(int[] x2) {

System.out.println(Arrays.toString(x));

int sum=0;

for(int i=0;i<x2.length;i++){

if(x[i]==1)

sum+=v[i];

}

maxValue=maxValue>sum?maxValue:sum;

if(maxValue<=sum)

System.arraycopy(x2, 0, jie, 0, x2.length);

}

public static void main(String[] args) {

int[] w = {6, 5, 2, 1, 1};//物品重量

int[] v = {48, 40, 12, 8, 7};//物品价格

int c=8; //背包容量

Ch11_11 ch=new Ch11_11(w,v,c);

System.out.println("全部解如下:");

ch.DP(0);

System.out.println("最优解是:"+Arrays.toString(ch.jie)+"\n最大值是:"+ch.maxValue);

}

}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值