问题描述
1 线性时间选择问题描述
问题一:随机给定一个数组,设计一个算法找出该数组中第k小元素。
2 最优装载问题描述
问题二:有一批集装箱要装上一艘载重量为c的轮船,其中集装箱i的重量为,体积无限制,xi=0表示不装入集装箱i,xi=1表示装入集装箱i将尽可能多地集装箱装上轮船。
3 符号三角形问题描述
问题三:符号三角形问题是指第一行有n个符号,对于给定的n,计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。
4 石子合并问题描述
问题四:在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆, 并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。
5 最小重量机器设计问题描述
问题五:设某一机器由n个部件组成,每种部件都可以从m个不同的供应商处购得。设wij是从供应商j处购得的部件i的重量,cij是相应的价格。设计一个优先队列式分支限界法,给出总价格不超过d的最小重量机器设计。
课程设计要求
为上述问题设计算法实现对问题的解,并用图形用户界面GUI输出,编程语言不限(本文使用的Java语言)。
程序代码
登录系统程序
package Design;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Login extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
//定义组件
JButton jb1,jb2=null;
JRadioButton jrb1,jrb2=null;
JPanel jp1,jp2,jp3,jp4,jp5=null;
JTextField jtf,yjtf,sjtf=null;
JLabel jlb1,jlb2,jlb3,jlb4=null;
JPasswordField jpf=null;
ButtonGroup bg=null;
//设定用户名和密码
final String stu_name="3180932029";
final String stu_pwd="111111";
final String tea_name="666";
final String tea_pwd="666";
String yzm="";
public Login()
{
//创建组件
jb1=new JButton("登录");
jb2=new JButton("重置");
//设置监听
jb1.addActionListener(this);
jb2.addActionListener(this);
jrb1=new JRadioButton("教师");
jrb2=new JRadioButton("学生");
bg=new ButtonGroup();
bg.add(jrb1);
bg.add(jrb2);
jrb2.setSelected(true);
jp1=new JPanel();
jp2=new JPanel();
jp3=new JPanel();
jp4=new JPanel();
jp5=new JPanel();
jlb1=new JLabel("用户名:");
jlb2=new JLabel("密 码:");
jlb3=new JLabel("权 限:");
jlb4=new JLabel("验证码:");
jtf=new JTextField(10);
jpf=new JPasswordField(10);
yjtf=new JTextField(5);
sjtf=new JTextField(4);
int i=4;
String s="";
while(i-->0) {
if(i%2==0) {
int x=(int) (Math.random()*10);
yzm=yzm+String.valueOf(x);
s=s+String.valueOf(x)+" ";
}
else {
char c=(char) ((97+(int) (Math.random()*26)));
yzm=yzm+String.valueOf(c);
s=s+String.valueOf(c)+" ";
}
}
sjtf.setText(s);
//加入到JPanel中
jp1.add(jlb1);
jp1.add(jtf);
jp2.add(jlb2);
jp2.add(jpf);
jp3.add(jlb4);
jp3.add(yjtf);
jp3.add(sjtf);
jp4.add(jlb3);
jp4.add(jrb1);
jp4.add(jrb2);
jp5.add(jb1);
jp5.add(jb2);
//加入JFrame中
this.add(jp1);
this.add(jp2);
this.add(jp3);
this.add(jp4);
this.add(jp5);
//设置布局管理器
this.setLayout(new GridLayout(5,1));
//给窗口设置标题
this.setTitle("登录系统");
//设置窗体大小
this.setSize(300,220);
//设置窗体初始位置
this.setLocation(600, 250);
//设置当关闭窗口时,保证JVM也退出
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//显示窗体
this.setVisible(true);
this.setResizable(true);
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand()=="登录")
{
//如果选中教师登录
if(jrb1.isSelected())
{
tealogin();
}else if(jrb2.isSelected()) //学生在登录系统
{
stulogin();
}
}else if(e.getActionCommand()=="重置")
{
clear();
clear1();
}
}
//学生登录判断方法
@SuppressWarnings("deprecation")
public void stulogin()
{
if(stu_name.equals(jtf.getText())&&stu_pwd.equals(jpf.getText())&&yzm.equals(yjtf.getText()))
{
// System.out.println("登录成功");
JOptionPane.showMessageDialog(null,"登录成功!","提示消息",JOptionPane.WARNING_MESSAGE);
clear();
dispose();
new Main();
}else if(jtf.getText().isEmpty()&&jpf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入用户名和密码!","提示消息",JOptionPane.WARNING_MESSAGE);
}else if(jtf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入用户名!","提示消息",JOptionPane.WARNING_MESSAGE);
}else if(jpf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入密码!","提示消息",JOptionPane.WARNING_MESSAGE);
}
else if(yjtf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入验证码!","提示消息",JOptionPane.WARNING_MESSAGE);
}else if(!yzm.equals(yjtf.getText()))
{
JOptionPane.showMessageDialog(null,"验证码错误!","提示消息",JOptionPane.ERROR_MESSAGE);
clear1();
int j=4;
String s="";
yzm="";
while(j-->0) {
if(j%2==0) {
int x=(int) (Math.random()*10);
yzm=yzm+String.valueOf(x);
s=s+String.valueOf(x)+" ";
}
else {
char c=(char) ((97+(int) (Math.random()*26)));
yzm=yzm+String.valueOf(c);
s=s+String.valueOf(c)+" ";
}
}
sjtf.setText(s);
}else
{
JOptionPane.showMessageDialog(null,"用户名或者密码错误!\n请重新输入","提示消息",JOptionPane.ERROR_MESSAGE);
//清空输入框
clear();
}
}
//教师登录判断方法
@SuppressWarnings("deprecation")
public void tealogin()
{
if(tea_name.equals(jtf.getText())&&tea_pwd.equals(jpf.getText())&&yzm.equals(yjtf.getText())&&yzm.equals(yjtf.getText()))
{
//System.out.println("登录成功");
JOptionPane.showMessageDialog(null,"登录成功!","提示消息",JOptionPane.WARNING_MESSAGE);
clear();
new Main();
}else if(jtf.getText().isEmpty()&&jpf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入用户名和密码!","提示消息",JOptionPane.WARNING_MESSAGE);
}else if(jtf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入用户名!","提示消息",JOptionPane.WARNING_MESSAGE);
}else if(jpf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入密码!","提示消息",JOptionPane.WARNING_MESSAGE);
}else if(yjtf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入验证码!","提示消息",JOptionPane.WARNING_MESSAGE);
}else if(!yzm.equals(yjtf.getText()))
{
JOptionPane.showMessageDialog(null,"验证码错误!","提示消息",JOptionPane.ERROR_MESSAGE);
clear1();
int j=4;
String s="";
yzm="";
while(j-->0) {
if(j%2==0) {
int x=(int) (Math.random()*10);
yzm=yzm+String.valueOf(x);
s=s+String.valueOf(x)+" ";
}
else {
char c=(char) ((97+(int) (Math.random()*26)));
yzm=yzm+String.valueOf(c);
s=s+String.valueOf(c)+" ";
}
}
sjtf.setText(s);
}else
{
JOptionPane.showMessageDialog(null,"用户名或者密码错误!\n请重新输入","提示消息",JOptionPane.ERROR_MESSAGE);
//清空输入框
clear();
}
}
//清空文本框和密码框
public void clear()
{
jtf.setText("");
jpf.setText("");
}
public void clear1() {
jpf.setText("");
yjtf.setText("");
}
}
主类程序
package Design;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class Main extends JFrame
{
Container container;
public Main()
{
this.setTitle("算法设计与分析课程设计系统");
this.setLocation(600, 250);
container = this.getContentPane();
container.setLayout(new BorderLayout());
JMenuBar menuBar = new JMenuBar();
buildMainMenu(menuBar);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
JTextArea textArea = new JTextArea();
textArea.setText("欢迎来到算法设计与分析课程设计系统");
textArea.setFont(new Font("宋体", Font.PLAIN, 20));
panel.add(textArea);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.setContentPane(panel);
this.setJMenuBar(menuBar);
this.setVisible(true);
this.setSize(600,450);
this.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e)
{
setVisible(false);
JFrame frame=new JFrame();
JPanel jp=new JPanel();
JLabel jl = new JLabel();
jl.setIcon(new ImageIcon("d:\\QQ\\pictures\\thanks.jpg"));
jl.setBackground(Color.BLACK);
jp.add(jl);
frame.add(jp);
frame.setTitle("结语");
frame.setLocation(600, 250);
frame.setLayout(new FlowLayout());
frame.setSize(280, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
});
}
});
}
public void buildMainMenu(JMenuBar menuBar)
{
JMenu fileMenu = new JMenu("文件(F)");//第一个菜单
JMenuItem exitMenuItem = new JMenuItem("退出");
exitMenuItem.addActionListener(new ExitActionListener());
fileMenu.add(exitMenuItem);
menuBar.add(fileMenu);
JMenu AlgMenu = new JMenu("算法(A)");//第二个菜单
AlgMenu.setMnemonic(KeyEvent.VK_A);//给菜单定义助记键
JMenuItem AlgItem = new JMenuItem("算法目录");
AlgItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L,ActionEvent.CTRL_MASK));//设定快捷键
AlgItem.addActionListener(new AlgItemActionListener());
AlgMenu.add(AlgItem);
menuBar.add(AlgMenu);
JMenu helpMenu = new JMenu("帮助(H)");//第三个菜单
helpMenu.setMnemonic(KeyEvent.VK_H);
JMenuItem aboutMenuItem = new JMenuItem("关于");
aboutMenuItem.setMnemonic(KeyEvent.VK_M);
aboutMenuItem.addActionListener(new AboutActionListener());
helpMenu.add(aboutMenuItem);
menuBar.add(helpMenu);
}
class AlgItemActionListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
new Algorithm();
}
}
class AboutActionListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String msg = "算法设计与分析课程设计系统\n设计人:裴洪泽 程泽 雷雅囡 舒奕云\n设计时间:2020-7-1";
String title = "关于";
JOptionPane.showMessageDialog(container, msg,title,JOptionPane.INFORMATION_MESSAGE);
}
}
class ExitActionListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
JFrame frame=new JFrame();
JPanel jp=new JPanel();
JLabel jl = new JLabel();
jl.setIcon(new ImageIcon("d:\\QQ\\pictures\\thanks.jpg"));
jl.setBackground(Color.BLACK);
jp.add(jl);
frame.add(jp);
frame.setTitle("结语");
frame.setLocation(600, 250);
frame.setLayout(new FlowLayout());
frame.setSize(280, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
});
}
}
public static void main(String[] args)
{
new Login();
}
}
其中thanks.jpg为
算法目录程序
package Design;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Algorithm extends JFrame {
private static final long serialVersionUID = 1L;
public Algorithm() {
JFrame frame=new JFrame();
frame.setTitle("算法目录");
frame.setLocation(500, 250);
JMenuItem filesearch = new JMenuItem("查找");
filesearch.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,ActionEvent.CTRL_MASK));//设定快捷键
filesearch.addActionListener(new Search());
JMenu file = new JMenu("文件");
file.add(filesearch);
JMenuBar mb = new JMenuBar();
mb.add(file);
frame.setJMenuBar(mb);
JButton q1 = new JButton("线性时间选择问题");
JButton q2 = new JButton("最优装载问题");
JButton q3 = new JButton("符号三角形问题");
JButton q4 = new JButton("石子合并问题");
JButton q5 = new JButton("最小重量机器设计问题");
ButtonGroup group = new ButtonGroup();
group.add(q1);
group.add(q2);
group.add(q3);
group.add(q4);
group.add(q5);
//frame.setLayout(new BorderLayout());
frame.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 12));
frame.add(q1);
frame.add(q2);
frame.add(q3);
frame.add(q4);
frame.add(q5);
q1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new Linearselect();
System.out.println("\n");
}
});
q2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new Optimalloading();
System.out.println("\n");
}
});
q3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new Symtriangle();
System.out.println("\n");
}
});
q4.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
new Stonemerge();
System.out.println("\n");
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
q5.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
new Minweight();
System.out.println("\n");
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
frame.setSize(600, 400);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
class Search implements ActionListener
{
JFrame jf=null;
JPanel jp1=null;
JPanel jp2=null;
JLabel jlb=null;
JTextField jtf=null;
JButton jb=null;
public void actionPerformed(ActionEvent e)
{
jf=new JFrame();
jp1=new JPanel();
jp2=new JPanel();
jlb=new JLabel("请输入检索问题:");
jtf=new JTextField(10);
jb=new JButton("检索");
jb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
check();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
jp1.add(jlb);
jp1.add(jtf);
jp2.add(jb);
jf.add(jp1);
jf.add(jp2);
jf.setLayout(new GridLayout(3,1));
//给窗口设置标题
jf.setTitle("算法目录检索");
//设置窗体大小
jf.setSize(300,200);
//设置窗体初始位置
jf.setLocation(200, 150);
//设置当关闭窗口时
jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//显示窗体
jf.setVisible(true);
jf.setResizable(true);
}
public void check() throws Exception {
if(jtf.getText().equals("线性时间选择问题")) {
JOptionPane.showMessageDialog(null,"查找成功!","提示消息",JOptionPane.WARNING_MESSAGE);
System.out.println("\n");
new Linearselect();
}
else if(jtf.getText().equals("最优装载问题")) {
JOptionPane.showMessageDialog(null,"查找成功!","提示消息",JOptionPane.WARNING_MESSAGE);
System.out.println("\n");
new Optimalloading();
}
else if(jtf.getText().equals("符号三角形问题")) {
JOptionPane.showMessageDialog(null,"查找成功!","提示消息",JOptionPane.WARNING_MESSAGE);
System.out.println("\n");
new Symtriangle();
}
else if(jtf.getText().equals("石子合并问题")) {
JOptionPane.showMessageDialog(null,"查找成功!","提示消息",JOptionPane.WARNING_MESSAGE);
System.out.println("\n");
new Stonemerge();
}
else if(jtf.getText().equals("最小重量机器设计问题")) {
JOptionPane.showMessageDialog(null,"查找成功!","提示消息",JOptionPane.WARNING_MESSAGE);
System.out.println("\n");
new Minweight();
}
else {
JOptionPane.showMessageDialog(null,"算法目录中不存在该问题!\n请重新输入","提示消息",JOptionPane.ERROR_MESSAGE);
clear();
}
}
public void clear()
{
jtf.setText("");
}
}
}
线性时间选择算法程序
package Design;
import java.util.Random;
import java.util.Scanner;
import javax.swing.JOptionPane;
public class Linearselect {
public Linearselect() {
Scanner sc=new Scanner(System.in);
int k,n,i;
System.out.println("问题一:2-9线性时间选择问题");
//System.out.println("请输入数组的大小:");
n=Integer.parseInt(JOptionPane.showInputDialog("请输入数组的大小:"));
//n=sc.nextInt();
int []a=new int[n];
//System.out.println("请输入数组的各个元素:");
for(i=0;i<n;i++)
{
//a[i]=sc.nextInt();
a[i]=Integer.parseInt(JOptionPane.showInputDialog("请输入数组的第"+(i+1)+"个元素:"));
}
//System.out.println("请输入要查找的第k小数:");
//k=sc.nextInt();
k=Integer.parseInt(JOptionPane.showInputDialog("请输入要查找的第k小数:"));
int result,p=0;
result=randomizedSelect(a, p, n-1, k);
String s="数组为:";
System.out.print("数组为:");
for(i=0;i<n;i++) {
System.out.print(a[i]+" ");
s=s+a[i]+" ";
}
System.out.println("\n查找的第"+k+"小数为:"+result);
String title="线性时间选择算法输出";
JOptionPane.showMessageDialog(null,s+"\n查找的第"+k+"小数为:"+result,title,JOptionPane.INFORMATION_MESSAGE);
sc.close();
}
public static int randomizedPartition(int[] a,int p,int r){
int i=random(p,r);
swap(a,i,p);//交换枢纽元素到区间左端
return partition(a,p,r);
}
/**
* 线性选择指定数组中第k小的元素
* @param a 指定数组
* @param p 区间左端
* @param r 区间右端
* @param k 数组的大小位置
* @return 返回指定数组中第k小的元素
**/
public static int randomizedSelect(int[] a,int p,int r,int k){
if(p==r)
return a[p];
int i=randomizedPartition(a,p,r);
int j=i-p+1;//左端元素个数
//第k小的元素在左端
if(k<=j)return randomizedSelect(a,p,i,k);
else//第k小的元素在右端,并且左端已经有j个比它小的元素
//所以只要找右端中的第k-j小的元素就可以
return randomizedSelect(a,i+1,r,k-j);
}
public static int random(int i,int j){
Random r=new Random();
return r.nextInt(j-i)+i;
}
public static int partition(int[] a,int p,int r){
int i=p,j=r+1;
int x=a[p];
while(true){
while(a[++i]<x&&i<r);
while(a[--j]>x);
if(i>=j)break;
swap(a,i,j);
}
a[p]=a[j];
a[j]=x;
return j;
}
public static void swap(int[] a,int i,int j){
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
最优装载算法程序
package Design;
import javax.swing.*;
class Element implements Comparable<Object>{
int w;//集装箱的重量
int i;//集装箱编号
public Element(int w, int i) {
super();//调用基类中的某一个构造函数
this.w = w;
this.i = i;
}
public int compareTo(Object obj) {//Object 是所有类的父亲
float weight=((Element) obj).w;
if(w<weight) return -1;
if(w==weight) return 0;
return 1;
}
public int getW() {
return w;
}
public void setW(int w) {
this.w = w;
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
class MergeSort {
public static void mergeSort(Element nums[],int low,int high){
if(low<high){//至少有两个元素
int mid=(low+high)/2;//取中点
//左边
mergeSort(nums,low,mid);
//右边
mergeSort(nums,mid+1,high);
//左右归并
merge(nums,low,mid,high);
}
}
private static void merge(Element[] nums,int low,int mid,int high) {
//合并c[1:m]和c[m+1:r]到d[l:r]
int i=low,j=mid+1,k=0;
Element temp[]=new Element[high-low+1];
//把数排好序放进temp数组中
while((i<=mid)&&(j<=high)){
//把小的的放进temp数组中
if(nums[i].getW()-nums[j].getW()<=0)
temp[k++]=nums[i++];
else
temp[k++]=nums[j++];
}
//若左边的先遍历完,则把右边剩下的放进temp数组中
while(i<=mid)
temp[k++]=nums[i++];
//若右边的先遍历完,则把左边剩下的放进temp数组中
while(j<=high)
temp[k++]=nums[j++];
// 把temp中的数放回nums数组中
for(int p = 0;p<temp.length;p++){
nums[low+p]=temp[p];
}
}
}
public class Optimalloading
{
//最优装载
/*float c:轮船的载重量,float[] w:第i个集装箱的重量,
* int[] x:取0或1 0代表不装入集装箱i,1代表装入集装箱i*/
public static int loading(int c,int[] w,int[] x){
int n=w.length;//n代表集装箱的个数
Element[]d=new Element[n];//n个存着集装箱编号和重量的Element元素组成一个数组
for(int i=0;i<n;i++)//n次循环,给数组中的每一个元素装上值
d[i]=new Element(w[i], i);
MergeSort.mergeSort(d,0,d.length-1);//数组中元素按照集装箱重量由小到大排序
int opt=0;
for(int i=0;i<n;i++) x[i]=0;//所有集装箱一开始都没有装上船,所以把x置为0
for(int i=0;i<n&&d[i].w<c;i++){
x[d[i].i]=1;//相应编号的集装箱的装入标志设为1
opt++;
c-=d[i].w;
}
return opt;//返回的是装入集装箱的个数
}
public Optimalloading() {
int c=50;
int[] w={7,35,25,15,10,4,3,2};
int[] x={0,0,0,0,0,0,0,0};
System.out.println("问题二:4-3最优装载问题");
System.out.println("最多装入"+loading(c, w, x)+"个集装箱");
String title="最优装载算法输出";
JOptionPane.showMessageDialog(null,"最多装入"+loading(c, w, x)+"个集装箱",title,JOptionPane.INFORMATION_MESSAGE);
}
}
符号三角形算法程序
package Design;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import javax.swing.*;
public class Symtriangle {
static int n;//第一行的符号个数
static int half;//n*(n+1)/4 即当前符号总数量的一半
static int count;//当前“+”或者“-”的个数
static int[][] p;//符号三角形矩阵
static long sum;//已找到的符号三角形的个数
static String str="";
public static float Compute(int t) {
n=t;
count=0;
sum=0;
half=n*(n+1)/2;
if(half%2==1)
return 0;
half=half/2;
p=new int[n+1][n+1];
backtrack(1);
JFrame jf=new JFrame();
jf.setLayout(new FlowLayout());
JPanel jp=new JPanel();
jp.setLayout(new BorderLayout());
JTextArea jta=new JTextArea(str,20,20);
jta.setFont(new Font("宋体", Font.PLAIN, 20));
jp.add(jta);
jf.add(jp);
jf.setTitle("符号三角形打印图");
jf.setLocation(400, 250);
jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
jf.setVisible(true);
jf.setSize(240,550);
return sum;
}
public static void backtrack(int m) {
if((count>half)||(m*(m-1)/2-count>half)) //减去不符合条件的子树
return;
if(m>n)
{
sum++;
//打印符号三角形
for(int i=1;i<=n;i++)
{
for(int k=1;k<i;k++)
{
System.out.print(" ");
str+=" ";
}
for(int j=1;j<=n;j++)
{
if(p[i][j]==0&&j<=n-i+1) {
System.out.print("+" + " ");
str+="+ ";
}
else if(p[i][j]==1&&j<=n-i+1) {
System.out.print("-" + " ");
str+="- ";
}
else {
System.out.print(" ");
str+=" ";
}
}
System.out.println();
str+="\n";
}
System.out.println();
str+="\n";
}
else
{
//每个位置都有两种情况0,1
for(int i=0;i<2;i++)
{
p[1][m]=i;
count+=i;//计算“-”的个数
//接下来绘制其余的n-1行
for(int j=2;j<=m;j++)
{
//通过异或的方式求其余行数的放置方式
p[j][m-j+1]=p[j-1][m-j+1]^p[j-1][m-j+2];
count+=p[j][m-j+1];
}
backtrack(m+1);
for(int j=2;j<=m;j++)
{
count-=p[j][m-j+1];
}
count-=i;
}
}
}
public Symtriangle(){
String title="符号三角形算法输出";
System.out.println("问题三:5-4符号三角形问题");
String s=JOptionPane.showInputDialog("请输入第一行符号个数x(x>2)");
JOptionPane.showMessageDialog(null,"输入成功,三角形打印中...");
int x=Integer.parseInt(s);
float SUM=Compute(x);
System.out.print("符号三角形总数:"+SUM);
JOptionPane.showMessageDialog(null,"符号三角形总数:"+SUM,title,JOptionPane.INFORMATION_MESSAGE);
}
}
石子合并算法程序
package Design;
import java.awt.Color;
import java.awt.FlowLayout;
import java.util.Arrays;
import javax.swing.*;
public class Stonemerge {
private static int n; //石子堆数
private static int[][] m; //最优值
private static int[][] s;
private static int[] a; //各堆石子数
private static int[] backup; //a的备份
private static int minScore; //最小得分
private static int maxScore; //最大得分
public Stonemerge() throws Exception{
//将石子堆数和随机生成的各堆石子数写入文件
/*int no=500;
String st=String.valueOf(no);
File f = new File("D://eclipse/PHZ/src/Design/dataset/500.txt");
FileOutputStream fop = new FileOutputStream(f);
OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
writer.append(st);
writer.append("\r\n");
while (no-->0){
int num=(int)(Math.random( )*no);
st=String.valueOf(num);
writer.append(st);
writer.append("\r\n");
}
writer.close();
//读取文件
BufferedReader bf=new BufferedReader(new FileReader("D://eclipse/PHZ/src/Design/dataset/4.txt"));
String textLine;
String str="";
while((textLine=bf.readLine())!=null){
str+=textLine+" ";
}
String[] numbers=str.split(" ");
int []number=new int[numbers.length];
for (int i = 0; i<numbers.length; i++)
number[i]=Integer.parseInt(numbers[i]);
bf.close();
*/
//n =number[0];
System.out.println("问题四:3-3石子合并问题");
n=Integer.parseInt(JOptionPane.showInputDialog("请输入石子堆数:"));
a = new int[2*n];
m = new int[2*n][2*n];
s = new int[2*n][2*n];
for(int i=1; i<=n; i++)
//a[i] =number[i];
a[i]=Integer.parseInt(JOptionPane.showInputDialog("请输入第"+i+"堆石子数:"));
//a会改变,备份一下
backup = Arrays.copyOf(a, 2*n);
long startTime1 = System.currentTimeMillis(); //获取开始时间
minScore = circleMerge(a,0);//type为0,最小得分
long endTime1 = System.currentTimeMillis(); //获取结束时间
System.out.println("最小得分程序运行时间:" + (endTime1-startTime1) + "ms"); //输出程序运行时间
//还原
m = new int[2*n][2*n];
//s = new int[2*n][2*n];
long startTime2 = System.currentTimeMillis(); //获取开始时间
maxScore = circleMerge(backup, 1);//type为1,最大得分
long endTime2 = System.currentTimeMillis(); //获取结束时间
System.out.println("最大得分程序运行时间:" + (endTime2-startTime2) + "ms"); //输出程序运行时间
System.out.println("最小得分:"+minScore);
System.out.println("最大得分:"+maxScore);
String title="石子合并算法输出";
JOptionPane.showMessageDialog(null,"最小得分程序运行时间:" + (endTime1-startTime1) + "ms"+
"\n最大得分程序运行时间:" + (endTime2-startTime2) + "ms"+
"\n最小得分: "+minScore+"\n最大得分:"+maxScore,title,JOptionPane.INFORMATION_MESSAGE);
JFrame frame=new JFrame();
JPanel jp=new JPanel();
JLabel jl = new JLabel();
jl.setIcon(new ImageIcon("d:\\QQ\\pictures\\time.png"));
jl.setBackground(Color.BLACK);
jp.add(jl);
frame.add(jp);
frame.setTitle("时间复杂度图像");
frame.setLocation(600, 250);
frame.setLayout(new FlowLayout());
frame.setSize(600, 500);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
//type=0: 最小得分; type=1: 最大得分
private static int circleMerge(int[] a, int type){
for(int i=1; i<=n-1; i++)
a[n+i] = a[i];
n = 2*n-1;
if(type == 0)
minSum(a);
else
maxSum(a);
n = (n+1)/2;
int mm = m[1][n];
for(int i=2; i<=n; i++)//圆排列 转化为 直线排列后,要遍历一下
if((type==0) && (m[i][n+i-1]<mm) || (type==1) && (m[i][n+i-1]>mm))
mm = m[i][n+i-1];
return mm;
}
public static void minSum(int[] a){
for(int i=2; i<=n; i++)
a[i] = a[i] + a[i-1];
for(int r=2; r<=n; r++)
for(int i=1; i<=n-r+1; i++){
int j = i+r-1;
int i1 = i+1;
int j1 = j;
if(s[i][j-1] > i)
i1 = s[i][j-1];
if(s[i+1][j] > i)
j1 = s[i+1][j];
m[i][j] = m[i][i1-1] + m[i1][j];
s[i][j] = i1;
for(int k=j1; k>=i1+1; k--){
int q = m[i][k-1] + m[k][j];
if(q < m[i][j]){
m[i][j] = q;
s[i][j] = k;//记录合并的断开位置k
}
}
m[i][j] = m[i][j] + a[j] -a[i-1];
}
}
public static void maxSum(int[] a){
for(int i=2; i<=n; i++)
a[i] = a[i] + a[i-1];
for(int r=2; r<=n; r++)
for(int i=1; i<=n-r+1; i++){
int j = i+r-1;
if(m[i+1][j] > m[i][j-1])
m[i][j] = m[i+1][j] + a[j] - a[i-1];
else
m[i][j] = m[i][j-1] + a[j] - a[i-1];
}
}
}
其中time.png为
该图是通过测试算法在不同规模的石子堆下运行时间,利用python绘制
最小重量机器设计算法程序
package Design;
/*
* 本代码运用优先队列式分支限界法解决了最小重量机器设计问题。
* 算法思路:对于在某一个供应商是否购买某一零件,可以将这个过程抽象化为子集树模型。
* 该树的第i层则代表第i个零件的购买情况,每个商家j对应一棵子树。从根节点开始,对于当前讨论的
* 节点我们将之当作扩展节点,遍历该扩展节点的所有子节点,将其中符合条件的子节点全部插入优先
* 队列中(判断条件运用剪枝函数,下面讨论)。当遍历完后,该节点成为死节点,从优先队列中取出
* 在当前情况下重量最小的节点继续向下进行迭代,直到到达某叶子节点后,记录下当前情况下的最小
* 重量,然后继续将优先队列中的活节点依次出队,直到优先队列为空,整个子集树只剩下一条最优路径。
*
* 剪枝函数:在对某个节点是否符合条件的判断中,采用了约束函数和限界函数的双重判断。
* 约束函数:对于该节点到最终叶子节点中所有节点价格的最小值的和超过了要求的节点,直接
* 置为死节点,不再放入优先队列,并且其子节点都不必再进行讨论。
* 限界函数:对于该节点到最终叶子节点中所有节点重量最小值的和已经大于了目前已经计算出的重量的最小值。
* 则直接置为死节点,不放入优先队列,并且其子节点都不必再进行讨论。
* */
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.PriorityQueue;
import javax.swing.*;
//定义节点类,分别存储该节点的层数level,该节点的父节点,从根节点到该节点的价值总和,重量总和
//该节点的商家序号。覆盖compareTo方法,优先按照重量对节点进行比较。
class Node implements Comparable<Node>{
int value = 0;
int weight = 0;
int level = 0;
int source = 0;
Node father = null;
public int compareTo(Node d){
if(this.weight<d.weight) return -1;
else if(this.weight==d.weight) return(this.value-d.value);
else return 1;
}
}
public class Minweight {
//以下讨论中,商品的重量存储在w[][]中,价格存储在c[][]中。角标全部从1开始。
//共有n个零件需要购买,同一个零件共有m个商家在销售,消费的上限为d。
public static void getMinWeight(int[][] c,int[][] w,int m,int n,int d){
//int minValue = Integer.MAX_VALUE;
int minWeight = Integer.MAX_VALUE;
//定义购买的路径数组。
int[] way = new int[n+1];
//定义优先队列。
PriorityQueue<Node> heap = new PriorityQueue<Node>();
//初始化一个全为0的节点,放入优先队列,开始循环。
Node initial = new Node();
heap.add(initial);
//只要优先队列非空,循环就继续下去,依次继续取出优先队列中的节点。
while(!heap.isEmpty()){
Node fatherNode = heap.poll();
//当取出的节点已经到达叶子节点时,如果所找到的这条路径的零件总重量小于之前的重量,则更新
//购买路径和当前已发现的最小重量。
if(fatherNode.level == n){
if(fatherNode.weight < minWeight){
minWeight = fatherNode.weight;
//minValue = fatherNode.value;
for(int i=n;i>=1;i--){
way[i] = fatherNode.source;
fatherNode = fatherNode.father;
}
}
}
//否则就对于取出的节点先进行剪枝判断。
else{
int min_weight = fatherNode.weight;
int min_value = fatherNode.value;
//遍历该节点到叶子节点后面的最优路径的所有节点。
for(int i = fatherNode.level+1;i<n+1;i++){
int temp_min_value = Integer.MAX_VALUE;
int temp_min_weight = Integer.MAX_VALUE;
//选取下面每一层中的重量最小的节点和价值最小的节点。
for(int j=1;j<m+1;j++){
if(c[i][j]<temp_min_value)
temp_min_value = c[i][j];
if(w[i][j]<temp_min_weight)
temp_min_weight = w[i][j];
}
//将能够获取到的理想最优值取出,看是否符合限界函数和约束函数。
//注意:此时的最优值不一定能同时取到,因为重量最优的点和价值最优的点不一定是同一个节点。
min_weight += temp_min_weight;
min_value += temp_min_value;
}
//对于宽约束都不能满足的节点,直接置为死节点,不再讨论其剩余节点。
if(min_weight > minWeight || min_value > d)
continue;
//剩下的能够符合要求的所有子节点全部放入到优先队列中去。
for(int i=1;i<m+1;i++){
if(fatherNode.value+c[fatherNode.level+1][i] <=d &&
fatherNode.weight+w[fatherNode.level+1][i]<minWeight){
Node newNode = new Node();
newNode.father = fatherNode;
newNode.level = fatherNode.level+1;
newNode.source = i;
newNode.value = fatherNode.value+c[fatherNode.level+1][i];
newNode.weight = fatherNode.weight+w[fatherNode.level+1][i];
heap.add(newNode);
}
}
}
}
//输出能够取得的最小重量和购买路径。
String s="";
System.out.println("问题五:6-4最小重量机器设计问题");
System.out.println("最小重量:"+minWeight);
System.out.print("购买路径:");
for(int i = 1;i<n+1;i++) {
System.out.print(way[i]+" ");
s=s+way[i]+" ";
}
String title="最小重量机器设计算法输出";
JOptionPane.showMessageDialog(null,"最小重量:"+minWeight+"\n购买路径:"+s,title,JOptionPane.INFORMATION_MESSAGE);
}
//主函数用于对各项数值进行初始化。从D盘input.txt文件下读取初始数值。
public Minweight() throws IOException{
int m,n,d;
BufferedReader bufr = new BufferedReader(new FileReader("D://eclipse/PHZ/src/Design/input.txt"));
String[] str = bufr.readLine().split(" ");
n = Integer.parseInt(str[0]);
m = Integer.parseInt(str[1]);
d = Integer.parseInt(str[2]);
int[][] c = new int[n+1][m+1];
int[][] w = new int[n+1][m+1];
for(int i=1;i<n+1;i++){
str = bufr.readLine().split(" ");
for(int j=1;j<m+1;j++)
c[i][j] = Integer.parseInt(str[j-1]);
}
for(int i=1;i<n+1;i++){
str = bufr.readLine().split(" ");
for(int j=1;j<m+1;j++)
w[i][j] = Integer.parseInt(str[j-1]);
}
//调用该函数得到结果。
getMinWeight(c,w,m,n,d);
bufr.close();
}
}
其中input.txt文件内容为
3 3 4
1 2 3
3 2 1
2 2 2
1 2 3
3 2 1
2 2 2
简单演示
课程设计最终版
演示视频好像不能全屏观看,画质不够清晰,请谅解(第一次制作)视频已投稿到B站(可全屏,画质清晰),链接为:
点击进入演示视频
心得体会
本次课程设计主要解决个问题,基于动态规划的石子合并问题和基于优先队列式分支限界法的最小重量机器设计问题。在设计过程中,主要自学了基于Java语言的GUI设计以及基于python的easygui的GUI设计,了解了JFrame各组件的功能和结构层次,将所有问题的算法输出图形化。另外,通过对问题的求解,对动态规划和优先队列式分支限界法有了更深刻的理解与把握。但是,在分析算法时间复杂度时遇到一些瓶颈,通过计算程序的平均运行时间并利用python的matplotlib画图得到的算法时间复杂度和理论分析有所差异,这需要仔细研究算法原理及过程,利用更精确的工具分析出算法的时间复杂度。总体而言,课程设计过程中感受到了Java语言的优越性、各种经典算法的高效性及GUI设计的趣味性。