D - Two out of Three CodeForces - 82D 记忆化搜索dp

题目链接:http://codeforces.com/contest/82/problem/D

 

题意:

        给你n个人需要被服务的时间,你每次可以从前三个里面选两个人一起服务,两个人必须一起开始一起结束,时间是max(a[i],a[j]),如果只剩下最后一个人则就服务其一个人,现在问你这n个人服务的总时长最短为多少,同时按照序号从小到大输出每一对被服务的人的下标。

 

做法:

       现场做我估计做不来,也是想了很久。。心累,网上大家的题解多都是dp[i][j]代表当前三个人中前两个人为第i个和第j个时候需要被服务的最短时间(i<j),这样的话,记忆化搜索,dp[i][j]就会等于max(a[i],a[j])+dfs(j+1,j+2)max(a[i],a[j+1])+dfs(j,j+2)max(a[j],a[j+1])+dfs(i,j+2)中的最小值,从后往前进行更新,那么就能很快的得到答案了,至于打印答案的话,只要验证到底是等于上面三个中的哪一个,继续搜索下去就好了。

 

再贴一个链接吧,另一种队友的有趣的做法:https://blog.csdn.net/jk_chen_acmer/article/details/88651230

 

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
typedef pair<int,int> pii;
typedef long long ll;
int dp[maxn][maxn],a[maxn],n;
int dfs(int x,int y){
    if(dp[x][y]) return dp[x][y];
    if(y==n+1)  return dp[x][y]=a[x];
    if(y==n) return dp[x][y]=max(a[x],a[y]);
    dp[x][y]=max(a[x],a[y])+dfs(y+1,y+2);
    dp[x][y]=min(dp[x][y],max(a[x],a[y+1])+dfs(y,y+2));
    dp[x][y]=min(dp[x][y],max(a[y],a[y+1])+dfs(x,y+2));
    return dp[x][y];
}
void pri(int x,int y){
    if(y==n+1){
        printf("%d\n",x);
        return ;
    }
    if(y==n){
        printf("%d %d\n",x,y);
        return ;
    }
    if(dp[x][y]==(max(a[x],a[y])+dp[y+1][y+2])){
        printf("%d %d\n",x,y);
        pri(y+1,y+2);
    }
    else if(dp[x][y]==(max(a[x],a[y+1])+dp[y][y+2])){
        printf("%d %d\n",x,y+1);
        pri(y,y+2);
    }
    else if(dp[x][y]==(max(a[y],a[y+1])+dp[x][y+2])){
        printf("%d %d\n",y,y+1);
        pri(x,y+2);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    dfs(1,2);
    printf("%d\n",dp[1][2]);
    pri(1,2);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值