10377: squee_spoon and his Cube III
Time Limit:2 Sec Memory Limit: 128 MB
Description
Input
Output
Sample Input
4 3 4 2 2
Sample Output
4
HINT
In the sample, we can divide all competitors into 3 groups:(1)(2)(3,4)
- At the beginning, 1st, 2nd and 3rd competitor started.
- At the end of 2 second, 3rd competitor finished. 4th competitor started.
- At the end of 3 second, 1st competitor finished.
- At the end of 4 second, 2nd and 4th competitor finished. All 4 persons has finished.
So the minimum total time is 4 seconds.
//偶然看到这篇博客,发现题很不错,就想着写一下,但却没啥思路,还是看大神的思路吧。。(没找到ZZuoj,所以也就没提交。。)
首先说下题意。就是一个比赛(安排得很紧凑),最多3个人同时比,每个人需要的时间是已知的,问最少总共花多少时间。或者可以想象成这样:三张桌子,一个选手比完下一个上。
问题就可以转化为:有一些数,分为三组,需要使得和最大的那组尽可能小。
这个问题可以通过dp(动态规划)来解决。dp(i,j)的第一维表示第一组的总时间,第二维表示第二组的总时间,第三组的总时间自然就是所有选手的时间之和减去前两组的时间。
首先初态是dp[0][0]=true。此时三组为空,安排每个选手上台比赛,尝试把当前的选手的时间a加入每个组。如果加入第一组,就加在第一维上;如果加入第二组,就加在第二维上;如果加入第三组,不需要操作。即:
if(dp[i][j]==true){
dp[i+a][j]=true;
dp[i][j+a]=true;
}
处理完所有选手后,我们就可以通过考察所有为true的dp[i][j],来找最小可能时间了。
但是,如果仅仅做到这一步,还是会超时。需要进行一些优化。考虑三组的时间是可以互换的,设总时间为tot,我们可以让前两组的时间<=tot/3+60。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
int dp[1010][1010];
int a[60];
int main()
{
int n,i,j,k;
int sum;
while(scanf("%d",&n)!=EOF)
{
sum=0;
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
int ans=sum/3+60;
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(k=0;k<n;k++)
{
for(i=ans;i>=0;i--)
{
for(j=ans;j>=0;j--)
{
if(dp[i][j])
{
dp[i+a[k]][j]=1;
dp[i][j+a[k]]=1;
}
}
}
}
int kk=sum;
for(i=0;i<kk;i++)
{
for(j=0;j<kk;j++)
{
if(dp[i][j])
{
int tmp=max(i,j);
tmp=max(tmp,sum-i-j);
kk=min(kk,tmp);
}
}
}
printf("%d\n",kk);
}
return 0;
}