input:
2 3 Computer 3 3 English 20 1 Math 3 2 3 Computer 3 3 English 6 3 Math 6 3
output:
2 Computer Math English 3 Computer English Math
题目大意:
n个作业,每个有也有截止日期和需要花费的天数。如果超过截止时间一天,分数-1,求如何安排作业的先后,让 扣的分数最少。
分析:
状态dp。比较巧妙,使用11111的数串表示第1,2,3,5,6的作业都完成了。所以对一个i状态的方案,枚举作 业j,求出完成作业j需要扣掉的分数。详细看代码。
code:
#define frp #include<bits/stdc++.h> using namespace std; typedef long long ll; const ll INF = 0x3f3f3f3f; const ll inf = 0x7fffff; const int maxn = 1<<15; const int MAXN = 10000; int dp[maxn],pre[maxn],T[maxn],deadline[50],cost[50]; string sub[50]; int t; void print(int x){ if(!x)return; print(x^(1<<pre[x])); cout<<sub[pre[x]]<<endl; } void solve() { cin>>t; while(t--){ int n; cin>>n; for(int i=0;i<n;i++){ cin>>sub[i]>>deadline[i]>>cost[i]; } int sum=1<<n; for(int i=1;i<sum;i++){ dp[i]=inf; for(int j=n-1;j>=0;j--){ int tmp=1<<j; //如果i方案里没有完成j作业,则continue; if(!(i&tmp))continue; tmp=i^tmp; //完成j作业所要扣的分数T[]数组是完成tmp的方案的天数 int minus=T[tmp]+cost[j]-deadline[j]; if(minus<0)minus=0; if(dp[tmp]+minus<dp[i]){ dp[i]=dp[tmp]+minus; T[i]=T[tmp]+cost[j]; pre[i]=j; } } } cout<<dp[sum-1]<<endl; print(sum-1); memset(pre,0, sizeof(pre)); } } int main() { ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); #ifdef frp freopen("D:\coding\c_coding\in.txt", "r", stdin); // freopen("D:\coding\c_coding\out.txt", "w", stdout); #endif solve(); return 0; }