hdu1074

hdu1074 Doing Homework
传送门
题意
\(n(1\leq n\leq 15)\)项作业,每项作业都有名称、提交截止日期和完成这项作业所花费的日期,逾期一天扣一分,计算完成所有作业所扣的分数的最小值,并且输出按照时间顺序完成的作业名称
\(n\)项作业按照字典序从小到大输入,如果答案不唯一,输出字典序最小的解
题解
由于\(n\)不超过\(15\),可以通过状态压缩表示所有作业完成的状态,\(1\)表示已完成,\(0\)表示未完成
从小到大枚举所有状态,对于每一种状态,枚举所有未完成的作业,设完成这一作业的状态为新状态,更新新状态最少的扣分以及是从哪个状态转移过来的
由于作业是按照字典序从小到大排列的,更新的新状态是最后完成的作业,字典序最小的解是将字典序较大的作业放在后面,所以每次从后向前枚举所有作业
从状态\((1<<n)-1\)到状态\(0\)逆向找到每一次完成的作业,可以确定完成作业的顺序
时间复杂度\(O(n*2^n)\)

#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<sstream>
#include<cmath>
#include<ctime>
#include<climits>
#include<algorithm>
#define LL long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define pi acos(-1.0)
#define eps 1e-6
#define lowbit(x) x&(-x)
using namespace std;

const int maxn=16;
int T,n,dp[1<<maxn],last[1<<maxn],sum[1<<maxn];
struct node{
    int d,cost;
    string name;
}a[maxn];
vector<string> ans;

int main(){
    std::ios::sync_with_stdio(false);
    cin>>T;
    while(T--){
        cin>>n;
        for(int i=0;i<n;i++){
            cin>>a[i].name>>a[i].d>>a[i].cost;
        }
        memset(sum,0,sizeof(sum));
        int sta=1<<n;
        for(int i=0;i<sta;i++){
            for(int j=0;j<n;j++){
                if(i&(1<<j)) sum[i]+=a[j].cost;
            }
        }
        memset(dp,0x3f,sizeof(dp));
        dp[0]=0;
        for(int i=0;i<sta;i++){
            for(int j=n-1;j>=0;j--){
                if(i!=(i|(1<<j))){
                    if(dp[i|(1<<j)]>dp[i]+max(0,sum[i|(1<<j)]-a[j].d)){
                        dp[i|(1<<j)]=dp[i]+max(0,sum[i|(1<<j)]-a[j].d);
                        last[i|(1<<j)]=i;
                    }
                }
            }
        }
        cout<<dp[sta-1]<<"\n";
        int s=sta-1;
        ans.clear();
        while(s){
            int t=last[s];
            for(int i=0;i<n;i++){
                if(((s>>i)&1)^((t>>i)&1)){
                    ans.push_back(a[i].name);
                    break;
                }
            }
            s=t;
        }
        for(int i=n-1;i>=0;i--) cout<<ans[i]<<"\n";
    }
    return 0;
}
posted @ 2020-08-27 20:54  fxq1304  阅读(110)  评论(0编辑  收藏  举报