题目链接: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