#狀壓dp#C 計劃帶師
阿新 • • 發佈:2020-11-02
分析
狀壓dp顯然,主要是字典序的問題,
考慮初態終態轉換就可以保證字典序最小了
程式碼
#include <cstdio> #include <cctype> #include <cstring> #define rr register using namespace std; const int N=21,M=1050011; char s[N][N*3]; int pre[M],dp[M],n,lim[N],two[N],a[N],sum[M],cho[M]; inline signed iut(){ rr int ans=0; rr char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } signed main(){ freopen("work.in","r",stdin); freopen("work.out","w",stdout); two[0]=1; for (rr int i=1;i<21;++i) two[i]=two[i-1]<<1; for (rr int i=0;i<21;++i) cho[two[i]]=i; for (rr int T=iut();T;--T){ n=iut(); for (rr int i=n-1;~i;--i){ scanf("%s",s[i]+1); lim[i]=iut(),a[i]=iut(); } memset(dp,42,sizeof(dp)),dp[two[n]-1]=0; for (rr int S=1;S<two[n];++S) sum[S]=sum[S&(S-1)]+a[cho[-S&S]]; for (rr int S=two[n]-1;S;--S){ for (rr int j=S;j;j&=j-1){ rr int i=cho[-j&j],t=0; if (sum[S]>=lim[i]) t=sum[S]-lim[i]; if (dp[S^two[i]]>dp[S]+t) dp[S^two[i]]=dp[S]+t,pre[S^two[i]]=i; } } printf("%d\n",dp[0]); for (rr int S=0;S!=two[n]-1;S^=two[pre[S]]) printf("%s\n",s[pre[S]]+1); } return 0; }