1,最优装载问题
问题描述:
有一批集装箱要装上一艘载重量为c的轮船。其中集装箱i的重 量为wi最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。
样例数据:
MAXWEIGHT 为 30
给定8个集装箱,重量分别为:[4, 10, 7, 11, 3, 5, 14, 2]。
算法分析
这是典型使用贪心算法解决的问题。
通过分析题目可以看到,小船的载重量(MAXWEIGHT)是固定的,要求装载的物品数量最多,那么应该优先选择把重量最小的物品装上船,然后不断装载剩余的物品,直到达到小船载重量的要求。
选择先装载重量最小的物品,这个选择策略就采用了贪心(Greedy)策略,从局部最优达到全局最优,从而产生最优装载问题的最优解。
源代码如下
import java.util.Arrays;
public class OptimizedLoading {
public static int MAXWEIGHT = 30;// 小船的载重量
public static int AMOUNT = 8;// 古董个数
/*
* 装载算法(贪心算法)
* */
public static int maxLoading(int[] weight) {
//计数器,用于记录装载到小船上古董的数量
int counter = 0;
// 对weight数组进行排序
Arrays.sort(weight);
int temp = 0; // 记录装载到船上的古董重量
for (int i = 0; i < AMOUNT; i++) {
temp += weight[i]; // 贪心策略:每次装入最轻者
if (temp <= MAXWEIGHT) // 若加入最轻者后还小于载重量,则古董个数+1
counter++;
else
//超重,不能装载
break;
}
//返回装载的古董的数量
return counter;
}
public static void main(String[] args) {
int ANSWER = 0; // 记录已装载的古董个数
int[] weight = { 4, 10, 7, 11, 3, 5, 14, 2 };
ANSWER = maxLoading(weight);
System.out.println("能装入的古董最大数量为: " + ANSWER);
}
}
2,活动安排问题
问题描述
设有n个活动的集合e={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间s_i和一个结束时间f_i,且s_i< f_i。如果选择了活动i,则它在半开时间区间[s_i,f_i]内占用资源。若区间[s_i,f_i]与区间[s_j,f_j]不相交,则称活动 i 与活动 j 是相容的。也就是说,当s_i ≥ f_i或s_j ≥ f_j时,活动 i 与活动 j 相容。活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合。
在下面所给出的解活动安排问题的贪心算法gpeedyselector中,各活动的起始时间和结束时间存储于数组s和f{中且按结束时间的非减序:.f_1 ≤ f_2 ≤ … ≤ f_n排列。如果所给出的活动未按此序排列,我们可以用o(nlogn)的时间将它重排。
源代码如下
package 贪心算法;
import java.util.Scanner;
public class Main活动安排问题 {
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
while(cin.hasNext())
{
//int num=cin.nextInt();
//for(int h=0;h<num;h++)
//{
int m=cin.nextInt();
int s[]=new int[m+1];
int []f=new int[m+1];
boolean []a=new boolean[m+1];
for(int j=1;j<=m;j++)
{
s[j]=cin.nextInt();
}
for(int k=1;k<=m;k++)
{
f[k]=cin.nextInt();
}
int n=s.length-1;
int count=1;
a[1]=true;
int j=1;
for(int i=2;i<=n;i++)
{
if(s[i]>=f[j])
{
a[i]=true;
j=i;
count++;
}else{
a[i]=false;
}
}
System.out.println(count);
for(int i=1;i<=n;i++)
{
if(a[i]==true)
{
System.out.println(i+" ");
}
}
}
System.out.println();
}
}
3,字符串重构问题
题目描述
给定一个字符串S,检查是否能重新排布其中的字母,使得两相邻的字符不同。
若可行,输出任意可行的结果。若不可行,返回空字符串。
示例 1:
输入: S = “aab”
输出: “aba”
示例 2:
输入: S = “aaab”
输出: “”
注意:
S 只包含小写字母并且长度在[1, 500]区间内。
源代码如下
public String reorganizeString(String S) {
int[] arr = new int[26];
int lenght = S.length();
if(S.length() == 1) return S;
char[] ret = new char[lenght];
int maxLength = 0;
for(char a: S.toCharArray()) {
if(maxLength < ++arr[a - 'a'])
maxLength = arr[a - 'a'];
}
if(maxLength * 2 - 1 > S.length())
return "";
int odd = 0, even = 1;
for(int i = 0; i < 26; i++) {
while(arr[i] > 0 && arr[i] < lenght / 2 + 1 && even < lenght) {
ret[even] = (char)(i + 'a');
arr[i] --;
even += 2;
}
while(arr[i] > 0) {
ret[odd] = (char)(i + 'a');
arr[i] --;
odd += 2;
}
}
return new String(ret);
}
4,01背包最大单位价值量
package 贪心算法;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
public class Main背包单位价值问题 {
private static class Node {
double v;
double w;
double vw;
}
private static class Reader {
static BufferedReader reader;
static StringTokenizer tokenizer;
static void init(InputStream input) {
reader = new BufferedReader(
new InputStreamReader(input));
tokenizer = new StringTokenizer("");
}
static String next() throws IOException {
while (!tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(
reader.readLine());
}
return tokenizer.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt(next());
}
static double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
public static void main(String[] args) {
try {
Reader.init(System.in);
while (true) {
int m = Reader.nextInt();
int n = Reader.nextInt();
if (n == -1 && m == -1) {
break;
}
List<Node> list = new ArrayList<Node>();
for(int i = 1;i <= n;i++){
Node node = new Node();
node.v = Reader.nextDouble();
node.w = Reader.nextDouble();
node.vw = node.v/node.w;
list.add(node);
}
Collections.sort(list, new Comparator<Node>() {
@Override
public int compare(Node o1, Node o2) {
if(o2.vw > o1.vw){
return 1;
}
else if(o2.vw < o1.vw){
return -1;
}
else
return 0;
}
});
double count = 0 ;
for(int i = 0; i < list.size();i++){
Node node = list.get(i);
if(m <= 0)
break;
else{
if(m - node.w >= 0){
count += node.v;
m -= node.w;
}
else{
count += m/node.w*node.v;
m = 0;
}
}
}
System.out.printf("%.3f\r\n",count);
}
}catch (Exception e){
}
}
}
5, java bean贪心问题
问题描述
FatMouse准备了M磅的猫粮,准备与守卫包含他最喜欢的食物JavaBean的仓库的猫交易。
仓库有N个房间。 第i个房间包含J [i]磅的JavaBeans并且需要F [i]磅的猫粮。
FatMouse不需要为房间里的所有JavaBeans进行交易,相反,如果他支付F [i] *a%磅的猫粮,他可能会得到J [i] *a%磅的JavaBeans。
这是一个实数。 现在他正在为你分配这个功课:告诉他他可以获得的最大JavaBeans数量。
源代码如下
package 贪心算法;
import java.text.DecimalFormat;
import java.util.Scanner;
public class JavaBean贪心算法贪javabing {
/**
* FatMouse准备了M磅的猫粮,准备与守卫包含他最喜欢的食物JavaBean的仓库的猫交易。
仓库有N个房间。 第i个房间包含J [i]磅的JavaBeans并且需要F [i]磅的猫粮。
FatMouse不需要为房间里的所有JavaBeans进行交易,相反,如果他支付F [i] *a%磅的猫粮,他可能会得到J [i] *a%磅的JavaBeans。
这是一个实数。 现在他正在为你分配这个功课:告诉他他可以获得的最大JavaBeans数量。
5 3
7 2
4 3
5 2
13.333
* @param args
*/
public static void main(String[] args) {
DecimalFormat df2 = new DecimalFormat("#.000");
Scanner cin=new Scanner(System.in);
int m;
int i,j,n;
double []a=new double[1000];
double []b=new double[1000];
double []c=new double[1000];
double sum=0,t;
while(cin.hasNext())
{
m=cin.nextInt();
n=cin.nextInt();
if(m!=-1&&n!=-1){
for(i=0;i<n;i++)
{
a[i]=cin.nextDouble();
b[i]=cin.nextDouble();
}
for(i=0;i<n;i++)
if(b[i]==0)
{
sum=sum+a[i];b[i]=-1;
}
for(i=0;i<n;i++)
c[i]=a[i]/b[i];
for(j=0;j<n-1;j++)
for(i=0;i<n-1-j;i++)
{
if(c[i]<c[i+1])
{
t=c[i];c[i]=c[i+1];c[i+1]=t;
t=a[i];a[i]=a[i+1];a[i+1]=t;
t=b[i];b[i]=b[i+1];b[i+1]=t;
}
}
for(i=0;i<n;i++)
{
if(b[i]!=-1)
{
if(m>=b[i]){
m=(int) (m-b[i]);
sum=sum+a[i];
}else{
sum=sum+c[i]*m;break;
}
}
}
System.out.println(df2.format(sum));
sum=0;
}
}
}
}
6,剪绳子问题
问题描述
给定一根长度为n的绳子,请把绳子剪成m段,每段绳子记为k[0],k[1]……k[m]。请问k[0]*k[1]……*k[m]可能的最大乘积是多少?例如:当绳子长度为8时,我们把它剪成长度分别为2,3,3段,此时最大乘积为18.
算法分析
从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止,这就是贪婪算法。
在剪绳子中,如果绳子的长度大于5,则每次剪出的长度为3的绳子。如果剩下的长度仍然大于5,则接着剪出一段长度为3的绳子,重复这个步骤,直到剩下的长度小于5.时间和空间复杂度都为O(1)。
源代码如下
public static int maxValue(int length) {
if (length < 2)
return 0;
if (length == 2)
return 1;
if (length == 3)
return 2;
int timesOf3 = length / 3; //剪长度为3的绳子段
if ((length - timesOf3 * 3) == 1) // 当长度为4的时候不能去用3剪
timesOf3 -= 1;
int timesOf2= (length - timesOf3* 3) / 2; // 这时应该把绳子剪成长度为2的两段:2*2>1*3
return ((int)(Math.pow(3, timesOf3))*((int)Math.pow(2, timesOf2)));
}