[状压DP] [省选联考 2020 A/B 卷] 信号传递

传送门

一眼求最优方案,DP
一眼 m m m巨小,状压
一眼状压DP,不会

集合为 S S S f [ S ] f[S] f[S]为答案, g [ i ] [ S ] g[i][S] g[i][S]为加入 i i i对点集 S S S的贡献
有转移方程:
f [ S + i ] = min ⁡ ( f [ S ] + g [ i ] [ S ] ) f[S+i]=\min(f[S]+g[i][S]) f[S+i]=min(f[S]+g[i][S])

暴力枚举 O ( m 2 2 m ) O(m^22^m) O(m22m)炸裂
考虑优化:
预处理优化
O ( m 2 m ) O(m2^m) O(m2m),但空间 O ( m 2 m ) O(m2^m) O(m2m),空间炸裂

考虑坎空间
按照二进制位枚数
需要理解lowbit函数的意义:二进制下最低的1位的数值

用一个val来记录每个点承受的费用,向右走就-1,向左走就*k(如: x → y , x ≤ y x\to y,x\le y xy,xy,给 x x x累加代价 − 1 × x -1\times x 1×x,给y累加代价 y y y

#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
	int i=0,f=1;char ch=0;
	while(!isdigit(ch)&&ch!='-') ch=getchar();
	if(ch=='-') ch=getchar(),f=-1;
	while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
	return i*f;
}

#define lowbit(x) (x)&(-(x))
const int N=2e5+5;
const int INF=1e9;
const int M=24;
int n,m,k,sz[1<<M],to[N],id[1<<M],rd[M][M],f[1<<M];
struct Cost{
    int pn,val[M];
}p1,p2;
queue<Cost>q;

int main(){
    n=in,m=in,k=in;
    for(int i=1;i<=n;++i) to[i]=in-1;
    for(int i=1;i<n;++i) ++rd[to[i]][to[i+1]];
    p1.pn=0;
    for(int i=0;i<m;++i){
        p1.val[i]=0;
        for(int j=0;j<m;++j){
            if(i==j) continue;
            p1.val[i]-=rd[i][j];
            p1.val[i]+=k*rd[j][i];
        }
    }
    q.push(p1);
    int tot=(1<<m)-1;
    for(int i=1;i<=tot;++i){
        f[i]=INF;
        sz[i]=sz[i>>1]+(i&1);
    }
    for(int i=1;i<=m;++i) id[(1<<i)]=i;
    while(!q.empty()){
        p1=q.front();q.pop();
        int siz=sz[p1.pn]+1;
        for(int i=tot^p1.pn;i;i^=lowbit(i)){
            int j=id[lowbit(i)];
            int tmp=f[p1.pn]+siz*p1.val[j];
            int sta=(p1.pn|(1<<j));
            f[sta]=min(f[sta],tmp);
        }
        for(int i=0;i<m;++i){
            if(p1.pn&(1<<i)) break;
            p2.pn=(p1.pn|(1<<i));
            for(int j=tot^p2.pn;j;j^=lowbit(j)){
                int r=id[lowbit(j)];
                p2.val[r]=p1.val[r]+(k*rd[r][i]+rd[i][r])-(-rd[r][i]+k*rd[i][r]);
            }
            q.push(p2);
        }
    }
    printf("%d\n",f[tot]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值