package monituihuo_wakuang;
import java.util.Random;
public class monituihuo_wakuang {
//挖金矿的例子
/*
* 有一个国家,所有的国民都非常老实憨厚,某天他们在自己的国家发现了十座金矿,并且这十座金矿在地图上排成一条直线,
国王知道这个消息后非常高兴,他希望能够把这些金子都挖出来造福国民,
首先他把这些金矿按照在地图上的位置从西至东进行编号,
依次为0、1、2、3、4、5、6、7、8、9,然后他命令他的手下去对每一座金矿进行勘测,
以便知道挖取每一座金矿需要多少人力以及每座金矿能够挖出多少金子,然后动员国民都来挖金子。
题目补充说明:
1)挖每一座金矿需要的人数是固定的,多一个人少一个人都不行。国王知道每个金矿各需要多少人手.
2)每一座金矿所挖出来的金子数是固定的.
3)开采一座金矿的人完成开采工作后,他们不会再次去开采其它金矿,因此一个人最多只能使用一次.
————————————————
输入文件名为“beibao.in”,因为这个问题实际上就是背包问题,所以测试数据文件名就保留原名吧。
输入文件第一行有两个数,第一个是国王可用用来开采金矿的总人数,第二个是总共发现的金矿数。
输入文件的第2至n+1行每行有两个数,第i行的两个数分别表示第i-1个金矿需要的人数和可以得到的金子数。
输出文件仅一个整数,表示能够得到的最大金子数。
输入样例:
100 5
77 92
22 22
29 87
50 46
99 90
输出样例:
133
*
* */
int max_n = 10;//总金矿数
int max_people=200;//可以用于挖金子的人数
int peopleNeed[] = {77,22,28,50,99,158,19,49,112,33};//每座金矿需要的人数
int gold[] = {92,22,87,46,90,300,32,44,130,50};//每座金矿能够挖出来的金子数
//初始化x,分别代表第i座金矿是否挖,0代表不挖,1代表挖
int x[] = new int[] {0,0,0,0,0,0,0,0,0,0};
//当前金矿挖取信息
int currentx[] = new int[10];
//取x时的金子数
int xEvaluation = 0;
int currentEvaluation = 0;
int bestEvaluation = -1;//等于-1时表示未知
int bestX[] = new int[10];
int T = 50;//降温次数
int bestT = 0;//最好的温度
int N = 500;//每次降温迭代的次数
private float a = 0.98f;//降温系数
private float t0 = 100f;//初始温度
Random random = new Random(System.currentTimeMillis());
//评价函数,就是能挖出来的金子数
public int evaluate(int[] x,int[] g) {
return getMatrix(x,g);
}
//初始化 xi
public void initX() {
for(int i=0; i<max_n; i++) {
int a = new Random().nextInt(2);//2控制着只取0或1两个数。
x[i] = a;
}
if(getMatrix(x, peopleNeed)>200) {
initX();
}
}
//取x附近的点
public void updateX(int[] x,int[] currentx) {
copyArray(x,currentx);
while(true) {
int ran1 = random.nextInt(65535)%max_n;//65535控制是正数,%max_n保证得到的数永远是0-max_n的数。
currentx[ran1] = (currentx[ran1]==1?0:1);
//满足条件则令tempx取x附近的值域
if(getMatrix(currentx, peopleNeed)<=200&&!isEqualX(x,currentx))
break;
}
}
//判断两个点是否重合
private boolean isEqualX(int[] x, int[] currentx) {
// TODO Auto-generated method stub
for(int i=0; i<x.length; i++) {
if(x[i] != currentx[i]) {
return false;
}
}
return true;
}
//复制数组
private void copyArray(int[] x, int[] tempx) {
// TODO Auto-generated method stub
for(int i = 1; i < max_n; i++) {
tempx[i] = x[i];
}
}
//实现数组相乘
private int getMatrix(int[] x, int[] y) {
// TODO Auto-generated method stub
int remax = 0;
for(int i=0; i<x.length; i++) {
remax += x[i]*y[i];
}
return remax;
}
//执行
public void solve() {
initX();
// System.out.print("initX: ");
// for (int i : x) {
// System.out.print(i + " ");
// }
System.out.println();
//默认当前最大
copyArray(x,bestX);
bestEvaluation = evaluate(x,gold);
int k = 0;//降温次数
int n = 0;//迭步次数
float t = t0;
while(k<T) {//温度控制
n=0;
while(n<N) {//迭代步数
//取x附近的点,其实就是在x数组范围内的随机一个点
updateX(x,currentx);
//求currentX时的评价函数
currentEvaluation = evaluate(currentx,gold);
//保存最大评价值
if(currentEvaluation > bestEvaluation) {
bestEvaluation = currentEvaluation;
copyArray(currentx,bestX);
bestT = k;
}
//评价函数的变化值
int delt = currentEvaluation - xEvaluation;
//如果评价函数值更大则进行更新,否则以一定概率更新
//由于我们这里求的是最大值,所以exp((delt)/t)
//若ΔT<0则接受S′作为新的当前解S,否则以概率exp(-ΔT/T)接受S′作为新的当前解S。
if(delt>0 || Math.exp((delt)/t) > random.nextFloat()) {
//Math.exp(x) 函数返回 e的x次方,x 表示参数,e 是欧拉常数(Euler's constant),自然对数的底数。
//b = random.nextFloat() 取值为[0.0,1.0)的数。
//将当前currentx保存至x中,x代表前一个状态,currentx代表当前状态,
//并更新当前评价函数值
copyArray(currentx, x);
xEvaluation = currentEvaluation;
}
n += 1;
}
t = a*t;
k += 1;
}
System.out.println("最佳长度");
System.out.println(bestEvaluation);
System.out.println("最佳路径: ");
for(int i=0; i< max_n; i++) {
System.out.println(bestX[i] + ",");
}
}
public static void main(String[] args) {
monituihuo_wakuang d = new monituihuo_wakuang();
d.solve();
}
}