《趣学算法》第二章 贪心算法代码实现(Java)

2.2最优装载问题

import java.util.Scanner;
import java.util.Arrays;

public class Test2_2 {
        public static void main(String[] args) {
            Scanner scanner=new Scanner(System.in);
            System.out.println("请输入载重量c及古董个数n:");
            int c=scanner.nextInt();                           //载重量
            int n=scanner.nextInt();                           //古董个数

            int[] weight=new int[n];
            System.out.println("请输入每个古董的重量:");
            for(int i=0;i<n;i++)
                weight[i]=scanner.nextInt();
            Arrays.sort(weight);

            int temp=0;                                        //记录装载到船上的古董重量
            int answer=0;                                      //记录已装载的古董个数
            for(int i=0;i<n;i++) {
                temp+=weight[i];                               //贪心策略:每次装入最轻者
                if(temp<=c)                                    //若加入最轻者后还小于载重量,则古董个数+1
                    answer++;
                else
                    break;
            }

            System.out.println("能装入的古董最大数量为answer="+answer);
            scanner.close();
        }
}

程序运行结果如下:
《《趣学算法》第二章 贪心算法代码实现(Java)》

2.3背包问题

/*阿里巴巴与四十大盗——背包问题*/
import java.util.Scanner;

class three {
    double w=0;               //每个宝物的重量
    double v=0;               //每个宝物的价值
    double p=0;               //性价比

}


public class Test2_3 {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入宝物数量n及毛驴的承载能力m:");
        int n=scanner.nextInt();               //表示n个宝物
        double m=scanner.nextDouble();         //表示毛驴的承载能力
        System.out.println("请输入每个宝物的重量和价值,用空格分开:");

        three[] s=new three[n];                //定义n长的数组存放宝物,数组类型是three型,即数组每位由重量、价格和性价比组成
        for(int i=0;i<n;i++) {
            s[i]=new three();
            s[i].w=scanner.nextDouble();
            s[i].v=scanner.nextDouble();
            s[i].p=s[i].v/s[i].w;
        }
        selectionSort(s);

        double sum=0;                          //表示贪心记录运走宝物的价值之和
        for(int i=0;i<n;i++) {
            if(m>s[i].w) {                     //如果宝物的重量小于毛驴剩下的承载能力
                sum+=s[i].v;                   //宝物价值之和增加
                m-=s[i].w;                     //毛驴承载能力减少
            }
            else {                             //如果宝物的重量大于毛驴剩下的承载能力,则进行部分装载
                sum+=m*s[i].p;                 //价值增加部分重量的价值
                break;
            }
        }

        System.out.println("装入宝物的最大价值Maximum value="+sum);
        scanner.close();
    }   

    public static void selectionSort(three[] array){          //运用选择排序将宝物按照性价比由大到小进行排序

        three temp=new three();
        for(int i=0;i<array.length-1;i++){      
            for(int j=i+1;j<=array.length-1;j++){ 
                 if(array[i].p<array[j].p){          
                    temp = array[i];                          //要将类的所有成员变量进行换位置,因为值是相互对应的
                    array[i] = array[j];
                    array[j] = temp;
                 }
            }
        }
    }
}

程序运行结果如下:
《《趣学算法》第二章 贪心算法代码实现(Java)》

2.4会议安排

import java.util.Scanner;

class Meet{
    int beg;                               //会议的开始时间
    int end;                               //会议的结束时间
    int num;                               //记录会议的编号
}

class SetMeet{
    private int n;                         //会议总数
    private int answer;                    //最大的安排会议总数
    private int last;                      //记录被选中会议的结束时间
    Meet[] meet=new Meet[1000];               //存放会议对象的数组

    /*读入数据*/
    public void init() {
        Scanner scanner=new Scanner(System.in);
        System.out.println("输入会议总数:");
        n=scanner.nextInt();    
        System.out.println("输入会议的开始时间和结束时间,以空格分开:");
        for(int i=0;i<n;i++) {
            meet[i]=new Meet();            //初始化对象
            meet[i].beg=scanner.nextInt();
            meet[i].end=scanner.nextInt();
            meet[i].num=i+1;
        }
        scanner.close();
    }

    public void solve() {
        selectionSort(meet);                                 //对会议按照结束时间由小到大排序
        System.out.println("排完序的会议时间如下:");
        System.out.println("会议编号 开始时间 结束时间");
        for(int i=0;i<n;i++) 
            System.out.println(" "+meet[i].num+" "+meet[i].beg+" "+meet[i].end);
        System.out.println();
        System.out.println("选择会议的过程:");
        System.out.println(" 选择第"+meet[0].num+"个会议");  //选中了第一个会议
        answer=1;
        last=meet[0].end;

        for(int i=1;i<n;i++) {                               //依次检查每个会议
            if(meet[i].beg>=last) {                          //如果会议i开始的时间大于等于最后一个选中的会议的结束时间
                System.out.println(" 选择第"+meet[i].num+"个会议");
                answer++;                                    //可安排的会议总数+1
                last=meet[i].end;                            //更新last为最后一个选中会议的结束时间 
            }
        }
        System.out.println("最多可以安排"+answer+"个会议");
    }

    public void selectionSort(Meet[] array){                 //运用选择排序对会议按结束时间由小到大排序

        Meet temp=new Meet();
        for(int i=0;i<n-1;i++){      
            for(int j=i+1;j<=n-1;j++){ 
                 if(array[i].end>array[j].end){          
                    temp = array[i];                          //要将类的所有成员变量进行换位置,因为值是相互对应的
                    array[i] = array[j];
                    array[j] = temp;
                 }
            }
        }
    }

}

public class Test2_4 {
    public static void main(String[] args) {
        SetMeet sm=new SetMeet();                             //创建对象
        sm.init();                                            //读入数据
        sm.solve();                                           //贪心算法求解
    }   
}

程序运行结果如下:
《《趣学算法》第二章 贪心算法代码实现(Java)》《《趣学算法》第二章 贪心算法代码实现(Java)》

2.6 哈夫曼编码

import java.util.Scanner;

/*结点类*/
class HNodeType{
    double weight;                           //权值
    int parent;                              //父亲结点
    int lchild;                              //左孩子
    int rchild;                              //右孩子
    char value;                              //该节点表示的字符 
}

/*编码类*/
class HCodeType{
    final int MAXBIT=100;
    int[] bit=new int[MAXBIT];               //存储编码的数组
    int start;                               //编码开始下标
}

public class Test2_6 {

    static final int MAXVALUE=10000;

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入结点个数:");
        int n=scanner.nextInt();

        HCodeType[] HuffCode=new HCodeType[n];                                        //定义一个编码类数组 
        HNodeType[] HuffNode=new HNodeType[2*n-1];                                    //定义一个结点类数组

        HuffmanTree(HuffNode,n);                                                      //构造哈夫曼树
        HuffmanCode(HuffNode,HuffCode,n);                                             //哈夫曼树编码

        //输出已保存好的哈夫曼编码
        for(int i=0;i<n;i++) {
            System.out.print(HuffNode[i].value+": Huffman code is: ");
            for(int j=HuffCode[i].start+1;j<n;j++)
                System.out.print(HuffCode[i].bit[j]);
            System.out.println();
        }
        scanner.close();
    }

    /*构造哈夫曼树*/
    public static void HuffmanTree(HNodeType[] HuffNode,int n) {
        Scanner scanner=new Scanner(System.in);
        int i,j,x1,x2;
        double m1,m2;
        for(i=0;i<2*n-1;i++) {                                                        //初始化存放哈夫曼树数组中的结点
            HuffNode[i]=new HNodeType();                                              
            HuffNode[i].weight=0;
            HuffNode[i].parent=-1;
            HuffNode[i].lchild=-1;
            HuffNode[i].rchild=-1;
        }

        for(i=0;i<n;i++) {                                                            //输入n个叶子结点的权值
            System.out.println("请输入第"+(i+1)+"个结点的字符和权值:");
            String str=scanner.next();
            HuffNode[i].value=str.charAt(0);
            HuffNode[i].weight=scanner.nextDouble();
        }

        for(i=0;i<n-1;i++) {                                                          //执行n-1次合并

            m1=m2=MAXVALUE;                                                           //存放无父节点且权值最小的两个结点的权值
            x1=x2=-1;                                                                 //权值最小的两个结点在数组中的下标
            for(j=0;j<n+i;j++) {                                                      //找出无父节点且权值最小的两个结点,合并成一颗二叉树
                if(HuffNode[j].weight<m1&&HuffNode[j].parent==-1) {
                    m2=m1;
                    x2=x1;
                    m1=HuffNode[j].weight;
                    x1=j;
                }
                else if(HuffNode[j].weight<m2&&HuffNode[j].parent==-1) {
                    m2=HuffNode[j].weight;
                    x2=j;
                }
            }

            //设置找到的两个结点的父节点的信息
            HuffNode[x1].parent=n+i;                                                   
            HuffNode[x2].parent=n+i;
            HuffNode[n+i].lchild=x1;                                                   //新结点的左孩子节点是权值最小的结点的下标
            HuffNode[n+i].rchild=x2;                                                   //新结点的右孩子节点是权值次小的结点的下标
            HuffNode[n+i].weight=m1+m2;                                                //权值是两个最小权值之和
            System.out.printf("x1和x2的权值分别是:%.2f %.2f",m1,m2);
            System.out.println();
        }
    }

    /*哈夫曼树编码*/
    public static void HuffmanCode(HNodeType[] HuffNode,HCodeType[] HuffCode,int n) {
        HCodeType cd=new HCodeType();                                                 //定义临时变量存放求解编码时的信息
        int c;                                                                        //表示结点下标变量
        int p;                                                                        //表示当前结点的父节点
        for(int i=0;i<n;i++) {                                                        //共有n个叶子结点
            HuffCode[i]=new HCodeType();
            cd.start=n-1;                                                             //从后往前存放
            c=i;
            p=HuffNode[c].parent;
            while(p!=-1) {                                                            //自底向上遍历,只要存在父节点就继续向上走
                if(HuffNode[p].lchild==c) {                                           //若当前结点是p的左孩子则编码0
                    cd.bit[cd.start]=0;
                }
                else {                                                                //右孩子则编码1
                    cd.bit[cd.start]=1;
                }
                cd.start--;                                                           //求编码的下一位
                c=p;                                                                  //变量上移,准备下一次循环
                p=HuffNode[c].parent;
            }

            //把叶子结点的编码信息从临时编码cd中复制到编码数组中
            for(int j=cd.start+1;j<n;j++) 
                HuffCode[i].bit[j]=cd.bit[j];
            HuffCode[i].start=cd.start;                                                //指向编码开始的前一位
        }
    }
}

程序运行结果如下:
《《趣学算法》第二章 贪心算法代码实现(Java)》

2.7最小生成树

import java.util.Scanner;

public class Test2_7 {

    static final int INF=0x3fffffff;
    static final int N=100;
    static boolean[] s=new boolean[N];                         //s[i]=true,说明顶点i已加入集合U中
    static int[] closest=new int[N];                           //表示集合V-U中顶点j到U集合的最邻近顶点
    static int[] lowcost=new int[N];                           //表示集合V-U中顶点j到U集合的最邻近距离

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("输入结点数n和边数m:");
        int n=scanner.nextInt();
        int m=scanner.nextInt();
        int[][] c=new int[n+1][n+1];                            //存放图的权值

        for(int i=1;i<=n;i++) {                                 //初始化邻接矩阵
            for(int j=1;j<=n;j++)
                c[i][j]=INF;
        }
        System.out.println("输入结点数u、v和边值w:");
        int u,v,w;
        for(int i=1;i<=m;i++) {
            u=scanner.nextInt();
            v=scanner.nextInt();
            w=scanner.nextInt();
            c[u][v]=c[v][u]=w;
        }
        System.out.println("输入任一结点u0:");
        int u0=scanner.nextInt();

        Prim(n,u0,c);                                           //求最小权值之和
        int sumcost=0;
        System.out.println("数组lowcost的内容为:");
        for(int i=1;i<=n;i++) {
            System.out.print(lowcost[i]+" ");
            sumcost+=lowcost[i];
        }
        System.out.println("最小的花费是:"+sumcost);
        scanner.close();
    }

    public static void Prim(int n,int u0,int[][] c) {
        s[u0]=true;                                             //初始时集合U中只有一个元素即u0
        for(int i=1;i<=n;i++) {                                 //初始化closest、lowcost和s数组
            if(i!=u0) {
                lowcost[i]=c[u0][i];
                closest[i]=u0;
                s[i]=false;                                     //除u0外其他顶点都不在集合U中
            }
            else
                lowcost[i]=0;
        }

        for(int i=1;i<=n;i++) {
            int temp=INF;
            int t=u0;
            for(int j=1;j<=n;j++) {                             //在集合V-U中寻找距离集合U最近的顶点t
                if(!s[j]&&lowcost[j]<temp) {                    //!s[j]说明j顶点在V-U中
                    t=j;
                    temp=lowcost[j];
                }
            }
            s[t]=true;                                          //将t加入集合U中
            for(int j=1;j<=n;j++) {                             //更新lowcost和closest
                if(!s[j]&&c[t][j]<lowcost[j]) {                 //与t相邻的顶点到U的距离小于原来到U的距离则更新
                    lowcost[j]=c[t][j];
                    closest[j]=t;
                }
            }
        }
    }

}

程序运行结果如下:
《《趣学算法》第二章 贪心算法代码实现(Java)》
Kruskal算法实现:

import java.util.Scanner;

class Edge{
    int u;               //边的两端点
    int v;
    int w;               //权值 
}

public class Test2_7_2 {
    static final int N=100;
    static int[] nodeset=new int[N];                                  //存放结点的集合号

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("输入结点数n和边数m:");
        int n=scanner.nextInt();
        int m=scanner.nextInt();
        Edge[] e=new Edge[m];                                         //存放m条边

        Init(n);                                                      //初始化
        System.out.println("输入结点数u、v和边值w:");
        for(int i=0;i<m;i++) {
            e[i]=new Edge();
            e[i].u=scanner.nextInt();
            e[i].v=scanner.nextInt();
            e[i].w=scanner.nextInt();
        }
        selectionSort(e);                                             //将边按权值从小到大排序
        int ans=Kruskal(n,m,e);
        System.out.println("最小的花费是:"+ans);
    }

    public static void Init(int n) {
        for(int i=1;i<=n;i++)
            nodeset[i]=i;                                             //每个结点对应一个集合
    }

    public static void selectionSort(Edge[] e) {                      //选择排序对边权值从小到大排序
        Edge temp=new Edge();
        for(int i=0;i<e.length-1;i++) {
            for(int j=i+1;j<=e.length-1;j++) {
                if(e[i].w>e[j].w) {
                    temp=e[i];
                    e[i]=e[j];
                    e[j]=temp;
                }
            }
        }
    }

    public static int Kruskal(int n,int m,Edge[] e) {
        int ans=0,j=0;                                                //用来控制已加入的边数
        for(int i=0;i<m;i++) {
            if(merge(e[i].u,e[i].v,n)) {                              //判断边的两端是否属于同一集合即是否构成回路
                ans+=e[i].w;                                          //若不构成回路则将改变加入
                if(++j==(n-1))                                        //加入n-1条边即可
                    return ans;                                       
            }
        }
        return 0;
    }

    public static boolean merge(int u,int v,int n) {                  //合并集合
        int p=nodeset[u];                                             //p为u结点的集合号
        int q=nodeset[v];                                             //去为v结点的集合号
        if(p==q)                                                      //说明u和v在一个集合中
            return false;
        for(int i=1;i<=n;i++) {
            if(nodeset[i]==q)
                nodeset[i]=p;                                         //将和v相同的集合中的结点改为u的集合号
        }
        return true;
    }
}
    原文作者:贪心算法
    原文地址: https://blog.csdn.net/zd454909951/article/details/78972058
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞