首先说下题意。就是一个比赛(安排得很紧凑),最多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<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
bool dp[1200][1200];
int a[60];
int main(){
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
int n;
while(cin>>n){
memset(dp,0,sizeof(dp));
int tot=0;
int test=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
tot+=a[i];
}
int end = tot/3+60;
dp[0][0]=1;
for(int k=0;k<n;k++){
for(int i=end;i>=0;i--){
for(int j=end;j>=0;j--){
if(dp[i][j]){
dp[i+a[k]][j]=1;
dp[i][j+a[k]]=1;
}
}
}
}
int ans=tot;
for(int i=0;i<=end;i++){
for(int j=0;j<=end;j++){
if(dp[i][j]){
int tmp=max(i,j);
tmp=max(tmp,tot-i-j);
ans=min(ans,tmp);
}
}
}
cout<<ans<<endl;
}
return 0;
} 这样就可以通过这道题了。如果想让程序跑得更快,可以进行进一步的优化,把合法状态专门存起来,不去扫描那些非法状态。
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
bool dp[1070][1070];
int a[60];
pair<int,int> piis[1100000];
int main(){
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
int n;
while(cin>>n){
memset(dp,0,sizeof(dp));
int tot=0;
int test=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
tot+=a[i];
}
int ans=tot;
int end = tot/3+60;
dp[0][0]=1;
piis[0]=make_pair(0,0);
int pos=1;
for(int k=0;k<n;k++){
for(int i=pos-1;i>=0;i--){
int x,y;
x = piis[i].first + a[k];
y = piis[i].second;
if(x<y)swap(x,y);
if(x<=end){
if(dp[x][y]==0){
dp[x][y]=1;
piis[pos++]=make_pair(x,y);
int tmp=max(x,y);
tmp=max(tmp,tot-x-y);
ans=min(ans,tmp);
}
}
x = piis[i].first;
y = piis[i].second + a[k];
if(x<y)swap(x,y);
if(x<=end){
if(dp[x][y]==0){
dp[x][y]=1;
piis[pos++]=make_pair(x,y);
int tmp=max(x,y);
tmp=max(tmp,tot-x-y);
ans=min(ans,tmp);
}
}
}
}
cout<<ans<<endl;
}
return 0;
} 这道题算是这场比赛唯一有"算法"的题,可能出得难了。希望各位学弟学妹不要灰心,暂时的失败是再正常不过的。。不要因此放弃提高自己的机会。
本文介绍了一种使用动态规划解决比赛时间优化的问题。目标是将选手的比赛时间分配到三个时间段,使得最长的时间段最短。通过二维DP数组记录不同组合的可能性,并优化搜索过程减少不必要的计算。
5572

被折叠的 条评论
为什么被折叠?



