题解:P3947 肝活动
今天刷状压 DP 题,发现有道题很熟悉,点进来一看才发现之前我在这题的讨论区修 markdown,今天正好回来把这题 A 了。
数据范围明示状压 DP。
设
题目要求字典序最小的顺序,可以用一个字符串数组 std::string 十分方便的提供了可以比较两个字符串字典序的方法,并且题目中 char 的大小就能记录下打的是什么歌,在记录的时候转 char 即可,最后输出的时候也能直接用,十分方便。
#include<bits/stdc++.h>
using namespace std;
int n,mn,T;
char name[25][50];
int t[25],m[25];
int dp[(1<<22)];
string s[(1<<22)];
int stime[(1<<22)];
//void print(int S){
// for(int i=1;i<=n;i++){
// cout<<(S&(1<<(i-1)));
// }
//}
//void prints(int S){
// for(int i=0;i<s[S].length();i++){
// cout<<name[s[S][i]]<<" ";
// }
//}
int main(){
//ios::sync_with_stdio(0);cin.tie(0);
//cin>>n>>mn>>T;
scanf("%d %d %d",&n,&mn,&T);
int ts=0;
for(int i=1;i<=n;i++){
//cin>>name[i]>>t[i]>>m[i];
scanf("%s %d %d",name+i,t+i,m+i);
ts+=t[i];
}
if(ts>T)printf("No Answer"),exit(0);
int temp0=(1<<n);
for(int S=1;S<temp0;S++){
for(int i=1;i<=n;i++){
if(S&(1<<(i-1))){
int last=S^(1<<(i-1));
if(!stime[S])stime[S]=stime[last]+t[i];
int sum=stime[last];
int temp=dp[last]+max(0,m[i]-(sum+t[i]));
if(temp>dp[S]){
dp[S]=temp;
s[S]=s[last]+(char)i;
}else if(temp==dp[S]){
s[S]=min(s[S],s[last]+(char)i);
}
}
}
//print(S);cout<<" "<<dp[S]<<" ";prints(S);cout<<endl;
}
int temp=(1<<n)-1;
int ans=dp[temp];
if(ans<mn)printf("No Answer"),exit(0);
printf("%d\n",ans);
int temp2=s[temp].length();
for(int i=0;i<temp2;i++){
printf("%s\n",name[s[temp][i]]);
}
return 0;
}
在第 if(s[S]>s[last]+(char)i)s[S]=s[last]+(char)i; 改成 s[S]=min(s[S],s[last]+(char)i); 就能瞬间压进