题意:从m门课选出n个排到n天,每天一门,难度须递增,每门课对应着一个作业量Xi,且Xi = Xi-1 + k or Xi - Xi-1 * k,总作业量要尽可能大,问能否排布,若能排布,求方案。

思路:比赛时企图用DFS暴搜,无奈超时,尝试各种优化都没成功,赛后看了题解才知道是DP,同时也发现很多时候能用搜索解决的题目如果用DP会省下很多时间!

  建立一个三维DP数组,dp[i][j][k],i表示第i天,j表示第i天时排了第j门课,k表示选择的作业量为第j门课作业区间的左端点+k。需要注意的地方是还应建立pre数组来标记DP路径。

代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;

struct subject{
    long long a,b;
    int c,id;
    bool operator<(subject& t){
        return c<t.c;
    }
}arr[60];
struct route{
    int addition,id;
    route(){}
    route(int x,int y):id(x),addition(y){}
}pre[60][60][120],ending;

int n,m,k;
long long dp[60][60][120];//day/num/work

bool makeDp(){
    memset(dp,-1,sizeof(dp));
    for(int j=1;j<=m;j++)
        for(long long i=arr[j].a;i<=arr[j].b;i++){
            dp[1][j][i-arr[j].a]=i;
        }
    for(int i=1;i<n;i++){
        for(int j=i;j<=m&&m-j>=n-i;j++){
            for(long long kk=arr[j].a;kk<=arr[j].b;kk++){
                if(dp[i][j][kk-arr[j].a]==-1)
                    continue;
                for(int jj=j+1;jj<=m;jj++){
                    if(arr[jj].c==arr[j].c)
                        continue;
                    if(k*kk>=arr[jj].a&&k*kk<=arr[jj].b){
                        if(dp[i+1][jj][k*kk-arr[jj].a]<dp[i][j][kk-arr[j].a]+k*kk){
                            dp[i+1][jj][k*kk-arr[jj].a]=dp[i][j][kk-arr[j].a]+k*kk;
                            pre[i+1][jj][k*kk-arr[jj].a]=route(j,kk-arr[j].a);
                        }
                    }
                    if(k+kk>=arr[jj].a&&k+kk<=arr[jj].b){
                        if(dp[i+1][jj][k+kk-arr[jj].a]<dp[i][j][kk-arr[j].a]+k+kk){
                            dp[i+1][jj][k+kk-arr[jj].a]=dp[i][j][kk-arr[j].a]+k+kk;
                            pre[i+1][jj][k+kk-arr[jj].a]=route(j,kk-arr[j].a);
                        }
                    }
                }
            }
        }
    }
    long long flag=-1;
    for(int i=n;i<=m;i++){
        for(long long j=arr[i].a;j<=arr[i].b;j++){
            if(flag<dp[n][i][j-arr[i].a]){
                flag=dp[n][i][j-arr[i].a];
                ending=route(i,j-arr[i].a);
            }
        }
    }
    if(flag!=-1)
        return true;
    return false;
}

void findAns(bool x){
    if(!x)
        cout<<"NO";
    else {
        cout<<"YES\n";
        vector<route> ans;
        route ha=ending;
        for(int i=n;i>=1;i--){
            ans.push_back(ha);
            ha=pre[i][ha.id][ha.addition];
        }
        for(int i=n-1;i>=0;i--){
            cout<<arr[ans[i].id].id<<" "<<arr[ans[i].id].a+ans[i].addition<<endl;
        }
    }
}

int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++){
        cin>>arr[i].a>>arr[i].b>>arr[i].c;
        arr[i].id=i;
    }
    sort(arr+1,arr+1+m);
    findAns(makeDp());
    return 0;
}
By xxmlala
01-15 04:32