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最小数字(包含该数)  

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

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

     *

实现思路:首先定义一个方法,使它能够产生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
{
/**

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

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

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

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

* @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提到最前面得到的数是N的4倍

 

 

public class Ch11_5
{
/**

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

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

代表的是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个评委为参赛选手打分,分数是1到100。选手最后的得分是:去掉一个最高分,去掉一个最低分,其余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; /*先假设当前的最大值max为0*/
min=100; /*先假设当前的最小值min为100*/
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 罗马数字

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

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件物品,其重量和价值如下:

物品一:6 公斤  48 元

物品二:5 公斤  40 元

物品三:2 公斤  12 元

物品四:1 公斤  8 元

物品五:1 公斤  7 元

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

 

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

 

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

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

m(i, j)是背包容量为j,可选物品为0,1,...,i时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 class Ch11_10
{
//背包容量
private int c;
//物品重量数组
private int[] w;
//物品价值数组
private int[] v;
private int[][] m;//m(i, j)是背包容量为j,可选物品为0,1,...,i时0-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);
}
}