题目链接:http://codeforces.com/contest/82/problem/D
题意:
给你n个人需要被服务的时间,你每次可以从前三个里面选两个人一起服务,两个人必须一起开始一起结束,时间是,如果只剩下最后一个人则就服务其一个人,现在问你这n个人服务的总时长最短为多少,同时按照序号从小到大输出每一对被服务的人的下标。
做法:
现场做我估计做不来,也是想了很久。。心累,网上大家的题解多都是dp[i][j]代表当前三个人中前两个人为第i个和第j个时候需要被服务的最短时间(i<j),这样的话,记忆化搜索,dp[i][j]就会等于、,中的最小值,从后往前进行更新,那么就能很快的得到答案了,至于打印答案的话,只要验证到底是等于上面三个中的哪一个,继续搜索下去就好了。
再贴一个链接吧,另一种队友的有趣的做法: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;
}