洛谷$P3959 [NOIp2017]$ 宝藏 状压$dp$

正解:状压$dp$

解题报告:

传送门$QwQ$

$8102$年的时候就想搞这题了,,,$9102$了$gql$终于开始做这题了$kk$

发现有意义的状态只有当前选的点集和深度,所以设$f_{i,j}$表示当前深度为$i$,选了的点集状态为$j$.

然后转移就$f_{i,S}=min(f_{i-1,S_0}+cost)$,其中$S_0$为$S$的子集,$cost$为$S xor S_0$中的所有点和$S_0$的连边乘以$i$.

正确性显然?然后说下就,这里是并没有限制一定是和第$i-1$层的点连边的嘛,这样看起来有锅但其实是没问题的$QwQ$.就因为这样显然只会导致更劣,但这个情况一定会在其他转移中被正确转移到,所以是没影响的(,,,我$484$讲得还是不太清楚,,,$umm$如果没懂直接在评论区问趴$kk$.

然后就做完了$QwQQQQQ.$

 

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define int long long
#define gc getchar()
#define ri register int
#define rb register bool
#define rc register char
#define lowbit(x) (x&(-x))
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)

const int N=15,inf=1e9;
int n,m,dis[N][N],f[N][1<<N],S,as,lg[1<<N];

il int read()
{
    ri x=0;rb y=1;rc ch=gc;
    while(ch!='-' && (ch<'0' || ch>'9'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il int cal(ri x,ri y)
{
    ri ret=0;
    while(x)
    {
        ri nw=lg[lowbit(x)],tmp=y,t=inf;x-=lowbit(x);
        while(tmp)t=min(t,dis[nw][lg[lowbit(tmp)]]),tmp-=lowbit(tmp);;ret+=t;
    }
    return ret;
}

signed main()
{
    freopen("3959.in","r",stdin);freopen("3959.out","w",stdout);
    n=read();m=read();memset(dis,63,sizeof(dis));
    rp(i,1,m){ri x=read()-1,y=read()-1,z=read();dis[x][y]=dis[y][x]=min(dis[x][y],z);}
    memset(f,63,sizeof(f));rp(i,0,n-1)f[0][1<<i]=0,lg[1<<i]=i;S=(1<<n)-1;
    rp(i,1,S){ri j=(i-1)&i;while(j){ri k=i^j,d=cal(k,j);rp(p,1,n-1)f[p][i]=min(f[p][i],f[p-1][j]+d*p);j=(j-1)&i;}}
    as=f[0][0];rp(i,0,n-1)as=min(as,f[i][S]);printf("%lld
",as);
    return 0;
}
View Code

 

原文地址:https://www.cnblogs.com/lqsukida/p/11623623.html