完全自己做的。WA了一炮long long ,WA了一炮排序,T了几炮,然后把三元的dp数组拆成几个2元的就过了
看来三元的dp数组还是慢。
一个人有n个朋友,有m个问题要解决,买一个显示器要b块钱,他的朋友能帮他解决一些问题,但是需要酬劳,也需要这个人有相应的显示器数量。现在这个人要解决所有的问题,问解决所有问题的最小花费是多少。
问题数量为20,2^20大概是100W的样子,然后100个朋友
很显然的dp[n][k]状态压缩来做
n可以取2来滚动
(后来看solution size最少的那份代码,它是没有滚动的,他的dp数组就1维,因为所有dp更新都是 自己=min(自己,之前的状态+一些花费)),这样的就可以随意更新(从前往后和从后往前都可以)
dp[i][j]代表第i个朋友,j代表问题的解决状态
dp[i][j]=min(dp[i][j],dp[i-1][j])
dp[i][j|friendx[i].can]=min(dp[i-1][j]+cost(显示器,请人),dp[i][j|friendx[i].can])
显示器的花费是这么处理的
之前先按照显示器的需要数量从大到小排序,然后顺着dp下来
Moni[i-1][j]是这个时候的显示器数量,然后看和需求friendx[i].need差多少,如果已经够了就不要,不够就要加上。
然后更新(如果dp[i-1][j]+cost(显示器+请人)能更新dp[i][j|friendx[i].can])
则更新显示器的数量Moni[i][j|friendx[i].can]=max(Moni[i][j|friendx[i].can],friendx[i].need);
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <iostream>
#include <ctime>
#include <algorithm>
using namespace std;
long long INF=(1<<29);
#define pb push_back
struct FRE{
long long x,k,m,pro;
}fre[111];
long long dp0[2][1111111];
long long dp1[2][1111111];
bool cmp(FRE S1,FRE S2){
return S1.k>S2.k;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("/home/rainto96/in.txt","r",stdin);
#endif
INF<<=33;
long long n,m,b;
cin>>n>>m>>b;
for(long long i=1;i<=n;i++){
long long x,k,m;
cin>>x>>k>>m;
long long pro=0;
for(long long j=1;j<=m;j++){
long long no_pro;cin>>no_pro;
pro|=(1<<(no_pro-1));
}
fre[i]=(FRE){x,k,m,pro};
}
sort(fre+1,fre+1+n,cmp);
/*if(b==830067068){
cout<<83528376862632587<<endl;
return 0;
}*/
for(long long i=0;i<=1;i++){
for(long long j=0;j<=((1<<m)-1);j++){
dp0[i][j]=INF;
}
}
dp0[0][0]=0;
long long SCREEN;
long long limit=((1<<m)-1);
for(long long i=1;i<=n;i++){
for(long long j=0;j<=limit;j++){
long long now=i&1;
long long pre=(i-1)&1;
if(dp0[pre][j]==INF) continue;
SCREEN=fre[i].k>dp1[pre][j]? (fre[i].k-dp1[pre][j])*b:0;
//cout<<SCREEN<<endl;
long long select=j|fre[i].pro;
if(dp0[now][select]>dp0[pre][j]+fre[i].x+SCREEN){
dp0[now][select]=dp0[pre][j]+fre[i].x+SCREEN;
dp1[now][select]=max(dp1[pre][j],fre[i].k);
}
if(dp0[pre][j]<dp0[now][j]){
dp0[now][j]=dp0[pre][j];
dp1[now][j]=dp1[pre][j];
}
}
}
if(dp0[n&1][(1<<m)-1]==INF){
cout<<-1<<endl;
}else{
cout<<dp0[n&1][(1<<m)-1]<<endl;
}
return 0;
}
最短代码长度的
事先从小到大排序好需要显示器的数量
然后一直更新 dp[所有问题都解决](仅仅包含请朋友的费用)+当前朋友需要的显示器的 花费的最小值
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const long long N=128,I=1LL<<60;
struct P{
int x,k,b;
bool operator<(const P& t)const{return k<t.k;}
}p[N];
long long n,m,b,v[1<<20],t=I;
int main(){
cin>>n>>m>>b;
for(int i=0,j;i<n && cin>>p[i].x>>p[i].k>>j ;++i)
for(int x;j-->0&&cin>>x;)
p[i].b|=1<<(x-1);
memset(v,0x3f,sizeof(v));
v[0]=0;
sort(p,p+n);
for(int i=0;i<n;++i){
for(int j=1<<m;j-->0;){
int b=j|p[i].b;
v[b]=min(v[b],v[j]+p[i].x);
}
t=min(t,v[(1<<m)-1]+p[i].k*b);
}
cout<<(t<I?t:-1)<<endl;
}