Title:
Portal
Train of thought:
We might as well start from the greedy point of view, for a given n tasks, we affirm that one is finished immediately and then do another. So we can conclude that the termination time for completing n tasks is fixed, that is, the sum of the time required for all tasks.
So dp[i] means the minimum deduction under state I. Every time we find another task under state i, we merge it with state I to update the next state.
Then we need to make sure that the dictionary tree is the smallest, because we find that there are only 15 digits at most, so we can use the fifteenth digit to hash it into a number, and then we just need to compare the numbers to know the size.
AC_Code
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <vector> #include <stack> using namespace std; const int maxn = 16; const int MAXN = (1<<15); const int inf = 1e8; struct P { int cost,lit; char name[110]; }s[maxn]; int n; char name[maxn][110]; long long dp[MAXN]; long long imp[MAXN]; int gettime(int x) { int sum =0; for(int i=0;x;i++) { if(x&1) sum += s[i].cost; x >>= 1; } return sum; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%s%d%d",s[i].name,&s[i].lit,&s[i].cost); } int up = (1<<n); for(int i=0;i<up;i++) { dp[i] = inf; imp[i]=0; } dp[0] =0; for(int i=0;i<up;i++) { int sums = gettime(i); // cout<<i<<' '<<dp[i]<<' '<<imp[i]<<endl; for(int j=0;j<n;j++) { int tmp = (1<<j); if((i&tmp)) continue; int news = (i|tmp); int val = (sums + s[j].cost <= s[j].lit ? 0:sums+s[j].cost-s[j].lit); if(val + dp[i] < dp[news]) { dp[news] = dp[i]+val; imp[news] = imp[i]*15+j; // cout<<news<<endl; } else if(val + dp[i] == dp[news]) { if(imp[i]*15+j < imp[news]) { imp[news] = imp[i]*15+j; } } } } stack<int> sta; printf("%d\n",dp[up-1]); for(int i=0;i<n;i++) { sta.push(imp[up-1]%15); imp[up-1] /=15; } while(!sta.empty()) { printf("%s\n",s[sta.top()].name); sta.pop(); } } return 0; }