CF 417D Cunning Gena [状压dp+排序]

来源:互联网 发布:openstack用哪些数据库 编辑:程序博客网 时间:2024/05/17 08:46

完全自己做的。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_backstruct 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_JUDGEfreopen("/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;}


0 0
原创粉丝点击