自己出的题 squee_spoon and his Cube III

        首先说下题意。就是一个比赛(安排得很紧凑),最多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; 
} 

        这道题算是这场比赛唯一有"算法"的题,可能出得难了。希望各位学弟学妹不要灰心,暂时的失败是再正常不过的。。不要因此放弃提高自己的机会。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值