最大工作量问题新的解法(不会证明)

上次说到的那个问题,是用暴力破解,但是我电脑跑到30位的时候就跑不动了,现在我想出一种新的算法,经过验证是对的,但是我无法证明这种算法的正确性,请数学大神帮我证明无比感谢,我再重新描述一下问题:

         小明的导师给小明分配任务,每天都有不为0的任务量,如20,40,10,20,但是小明有心脏有问题,最多连续工作两天就必须休息一天,这让小明的导师很头疼,请问如果给定任务列表,小明怎么安排才能做最多的工作,求小明最多干多少活。

我的思路是这样的:每一天只有两种状态,一种是工作,一种是休息,我们就取到当天为止最大的工作量,所以要记录小明已经连续工作的天数,如果小明已经连续工作零天,那么当天必须工作才能获取的最大值,(我们把工作的顺序记录下来1表示工作,0表示休息,最终以便求和);如果小明已经工作一天那么,就让小明今天也工作才能达到最大值;如果说小明已经连续工作了两天,那我们先把今天休息,然后算出最大工作量然后记录下来,然后如果今天选择工作的话,那么就必须昨天休息,或者是前天休息,才能让今天继续工作,所以分别把昨天休息,和前天休息的最大工作量算出来,然后比较这三种工作量,取最大的工作量,然后把对应最大工作量的顺序记录下来。然后再进行下一天的决策。

        注意上面是我递推的思路,即(d代表工作天数,max代表当前最大工作量,work代表当天的工作量)

        if d<=1

        max=max+    work;

        else

        max=max{  3中决策的最大工作量 };


需要注意的是,每次要决策完后一定要把决策的工作序列记录下来,以便后面调用,如  1101等等,这个算法可以说是一种动态规划算法,也可以说是一种贪心算法,现在就是没有证明这种算法的正确性,请大神证明:我的实现如下(java)


public class Main3 {


static class Node{
boolean[] all=null;
int index=0;
int days=0;

public Node(int length){
all=new boolean[length];
}

public int sum(int[] workList){
int sum=0;
for(int i=0;i<index;i++){
if(all[i]){
  sum+=workList[i];
}
}
return sum;
}

public static Node max(Node a,Node b,int[] workList){
return a.sum(workList)>b.sum(workList)?a:b;
}

public static Node max(Node a,Node b,Node c,int[] workList){
Node temp=max(a,b,workList);
return max(temp,c,workList);
}

public void copy(Node node){
for(int i=0;i<index;i++){
node.all[i]=all[i];
node.index=index;
node.days=days;
}
}
}

public static int getMax(int[] workList){
if(workList.length<=2){
int sum=0;
for(Integer temp:workList){
sum+=temp;
}
return sum;
}else{
Node pre=new Node(workList.length);
pre.all[0]=true;
pre.all[1]=true;
pre.index=2;
pre.days=2;
Node now=null;
for(int i=2;i<workList.length;i++){

if(pre.days==2){
//这一天休息创建一个Node
Node a=new Node(workList.length);
pre.copy(a);
a.days=0;
a.all[a.index]=false;
a.index++;
//这一天上班,但是让昨天不上班
Node b=new Node(workList.length);
pre.copy(b);
   b.days=1;
   b.all[b.index]=true;
   b.all[b.index-1]=false;
   b.index++;
   //这一天上班,但是让前天天不上班
   Node c=new Node(workList.length);
   pre.copy(c);
   c.all[c.index]=true;
   c.all[c.index-2]=false;
c.index++;
//选取最大值
now=Node.max(a, b, c, workList);
}else{
//如果这已经工作天数不是2,那么今天工作肯定达到目前最大值
Node d=new Node(workList.length);
pre.copy(d);
d.days=pre.days+1;
d.all[d.index]=true;
d.index=pre.index+1;
now=d;
}
pre=now;
}
return now.sum(workList);
}
}

public static void main(String[] args) {
int[] workList=new int[]{2000,10,2000,2000};
System.out.println(getMax(workList));
}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值