pku 1011 解题报告

题目链接:http://acm.pku.edu.cn/JudgeOnline/problem?id=1011

解题思路:

      将读入的sticks按长度从大到小排序,并对每一个stick设置一个使用标准,如果该stick未使用,则对应的标志设置为1,否则设置为0。在读入sticks的过程中,将sticks的长度值累加,同时记录最长度stick,作为结果的最初试探值max,当该值不能被长度之和整除或者经过判断,不是所求结果时,将试探值增加1,直到找到结果,并输出结果。

       1 判断试探值是否为所求结果过程,首先判断试探值是否能被stick长度和整除,如果不能,则试探值增加1;如果能被整除,将试探值作为长度剩余值tmax,设置查找stick的开始编号为0,执行步骤2,如果不恩那个整除,则将max加1,执行步骤1 。

       2 tmax减stick的过程中,如果tmax不为0,且tmax小于剩余sticks中的最小值,则将tmax和减去的stick编号退栈,将该编号的stick设置为未使用,当栈完全弹出时,则该试探值不是所求的结果,试探值max自增1;如果退栈后,栈中还有元素,将剩余值栈顶元素设置为tmax,将该tmax上次将减去的stick的编号加1作为寻找要减去stick的开始编号,退栈后继续判断tmax是否等于max,如果是,继续退栈,并设置相应的stick为未使用,并判断栈是否为空,如果是则断定试探值max不是所求的结果,max自增1执行步骤1;将开始查找的stick的编号设置为退栈stick编号加1,否则重复步骤2。如果tmax不小于剩余sticks的最小值,执行步骤3.

       3 判断tmax是否大于从寻找stick编号开始剩下的所有长度之和,如果是,则将tmax和减去的stick编号退栈,将该编号的stick设置为未使用,当栈完全弹出时,则该试探值不是所求的结果,试探值max自增1;如果退栈后,栈中还有元素,将剩余值栈顶元素设置为tmax,将该tmax上次将减去的stick的编号加1作为寻找要减去stick的开始编号,重复步骤2。如果不是大于剩余值之和,执行步骤4.

       4 选取减去满足条件的stick。并修改相应的栈和stick标记。当减去的stick后,tmax为0,则将tmax设置为试探值,并记录前面减除的所有sticks的长度除以试探值的所得数目tmaxcount,从记录sticks的队列开始,数tmaxcount个stick,当有stick为被使用,则可以断定该试探值max不是所求结果,试探值max加1,回到步骤1。如果前tmaxcount个stick都使用过,则执行步骤2。当减去stick后,tmax不为0,则执行步骤2。当没有找到满足条件的stick时,执行步骤5 。

      5 将tmax和减去的stick编号退栈,将该编号的stick设置为未使用,当栈完全弹出时,则该试探值不是所求的结果,试探值max自增1;如果退栈后,栈中还有元素,栈顶元素设置为tmax,继续判断tmax是否等于max,如果是,继续退栈,并将相应的stick设置为为使用,并判断栈是否为空,如果是则断定试探值max不是所求的结果,max自增1,执行步骤1;否则将开始查找stick的编号设置为退栈stick的编号加1,重复步骤2。

 

 

代码:

#include <stdio.h>
#include<stdlib.h>
int main()
{
 int n,i,max,sum,subsum;
 int *pv, *ptag,p,j,count,tmax,min;
 int *premain, *psub, subcurr, pre,tag,isend,countmax,k;
 scanf("%d",&n);
 while(n!=0){
  max=0;sum=0;tag=0;
  pv=(int *)malloc(sizeof(int)*n);
  ptag=(int *)malloc(sizeof(int)*n);
  premain=(int *)malloc(sizeof(int)*(n+1));
  psub=(int *)malloc(sizeof(int)*(n+1));
  p=0;
  count=0;
  while(count<n){
   scanf("%d",&i);
   sum+=i;//累加所有sticks的和
   if(max<i)
    max=i;//找sticks的最大值
   j=p-1;
   if(p==0)
    pv[p]=i;
   else{
    while(j>=0){
     if(pv[j]>=i)
      break;
     else{
      pv[j+1]=pv[j];
      j--;
     }
    }
    pv[j+1]=i;
   }
   p++;
   count++;
  }
  while(max<=sum){
   if(sum%max==0){//判断试探值max是否能被sum整除
    for(i=0;i<n;i++)
     ptag[i]=1;//对于每一个试探值开始的时候,将所有stick设置为未使用
    count=0;tmax=max;premain[0]=max;pre=0;tag=0,isend=0,countmax=0;
    while(count<n){
     for(i=n-1;i>=0;i--){
      if(ptag[i]==1){//找出剩余stick中的最小值
       min=pv[i];
       break;
      }
     }
     if(tmax>=min){//剩余值tmax是否大于所有剩余值的最小值
      if(tmax==max&&tag==0)//当一个减完sticks凑齐一个max后,tmax从新设置为max,从所有sticks的开始编号查找stick
       j=0;
      else{//否则更加判断过程中的编号开始查找
      }
      subsum=0;
      /*for(k=j;k<n;k++){
       if(ptag[k]==1)
        subsum+=pv[k];
      }
      if(tmax>subsum){
       j=n;
      }*/
      for(;j<n;j++){
       if(ptag[j]==1){
        if(tmax-pv[j]==0){//凑齐一个max
         ptag[j]=0;
         count++;
         psub[pre]=j;
         pre++;
         premain[pre]=max;
         tmax=max;
         tag=0;
         countmax++;//凑齐的max数据
         for(k=0;k<countmax;k++)//查看所有stick的前countmax个stick是否被使用
          if(ptag[k]!=0){//如果前countmax个sticks中有没被使用的,则断定试探值max不是所求结果,设置退出标记
           isend=1;
           break;
          }
         break;
        }
        else if(tmax-pv[j]>=min){//没有凑齐一个max,但是找到满足减去的stick
         ptag[j]=0;
         count++;
         psub[pre]=j;
         pre++;
         premain[pre]=premain[pre-1]-pv[j];
         tmax=tmax-pv[j];
         j=psub[pre-1]+1;
         tag=1;
         break;
        }
        else{//继续查找满足的stick
         while(pv[j]==pv[j+1])
          j++;
        }
       }
      }
      if(isend)//判断是否退去该max的判断
       break;
      if(j==n){//没有找到满足条件的stick,对以前减除的stick进行退栈
       count--;
       pre--;
       if(pre<0)//当栈为空时,断定该max不是结果,退去该max的判断过程
        break;
       else{//退栈操作,并恢复相应的stick为未使用
        ptag[psub[pre]]=1;
        tmax=premain[pre];
        j=psub[pre]+1;
        while(pv[j-1]==pv[j])
         j++;
       }
       if(premain[pre]==max){//判断栈顶tmax是否为max,如果是,继续退栈,并做相应的设置和判断
        countmax--;//退出一个max后,将凑齐的max数目减1
        count--;
        pre--;
        if(pre<0)
        break;
        else{
         ptag[psub[pre]]=1;
         tmax=premain[pre];
         j=psub[pre]+1;//设置开始查找stick的编号
         while(pv[j-1]==pv[j])
          j++;
        }
       }
      }
     }
     else{//当tmax小于剩余的sticks中的最小值时,退栈,并做相应的设置和判断
      count--;
      pre--;
      if(pre<0)
       break;
      else{
       ptag[psub[pre]]=1;
       tmax=premain[pre];
       j=psub[pre]+1;//设置开始查找stick的编号
       
       while(pv[j-1]==pv[j])
         j++;
      }
      if(premain[pre]==max){//判断栈顶tmax是否为max,如果是,继续退栈,并做相应的设置和判断
        countmax--;退出一个max后,将凑齐的max数目减1
        count--;
        pre--;
        if(pre<0)
        break;
        else{
         ptag[psub[pre]]=1;
         tmax=premain[pre];
         j=psub[pre]+1;//设置开始查找stick的编号
         while(pv[j-1]==pv[j])
          j++;
        }
      }
     }
    }
    if(count==n&&tmax==max){//如果所有的sticks都用来凑齐max,且tmax剩余为0(因为没凑齐一个max,tmax将设置为max)
     printf("%d/n",max);
     break;
    }
    else
     max++;
   }
   else
    max++;
  }
  free(pv);
  free(ptag);
  free(psub);
  free(premain);
  scanf("%d",&n);
 }
 return 0;
}

 

测试用例:

9
15 3 2 11 4 1 8 8 8

6
6 2 2 4 8 8

5
1 1 1 1 1 

2
1 1

4
2 2 9 9

3
1 2 3

64
40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 
40 40 43 42 42 41 10 4 40 40 40 40 40 40 40 40 40 40 40 40 40 
40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 
40 

7
49 48 47 46 45 44 43

7
3 4 5 5 5 5 13

7
2 7 7 7 7 10 20

6
1 2 3 11 11 20

7
63 2 44 12 60 35 60 

9
5 2 1 5 2 1 5 2 1

4
1 2 3 4

64
32 32 32 32 32 32 32 32 32 32
32 32 32 32 32 32 32 32 32 32
32 32 32 32 32 32 32 32 32 32
32 32 32 32 32 32 32 32 32 32
32 32 32 32 32 32 32 32 32 32
32 32 32 32 32 32 32 32 32 32
33 33 31 31

64
40 40 30 35 35 26 15 40 40 40 40 40 40 40 40 40 40 40 40 40 40 
40 40 43 42 42 41 10 4 40 40 40 40 40 40 40 40 40 40 40 40 40 
40 25 39 46 40 10 4 40 40 37 18 17 16 15 40 40 40 40 40 40 40 
40
45
15 3 2 11 4 1 8 8 8 15 3 2 11 4 1 8 8 8 15 3 2 11 4 1 8 8 8 15 3 2 11 4 1 8 8 8
15 3 2 11 4 1 8 8 8
0

结果:
20
10
1
1
11
3
1251
322
20
30
24
276
6
5
64
454
20
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值