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
{
/**
* 实现思路:1 将两个超长的整形转换为字符串
* 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提到最前面得到的数是N的4倍
public class Ch11_5
{
/**
* 问题分析:1 假设这个数是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个评委为参赛选手打分,分数是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);
}
}