专栏文章

题解:CF1846G Rudolf and CodeVid-23

CF1846G题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mip1tu7r
此快照首次捕获于
2025/12/03 04:46
3 个月前
此快照最后确认于
2025/12/03 04:46
3 个月前
查看原文

Solution CF1846G

Idea

注意到 n10n\le 10,这启示我们状压,毕竟最多只有 210=10242^{10}=1024 种状态。
然后最短路转移就枚举初始状态 uu,然后就考虑吃第 ii 种药。第 ii 种药会治好 xix_i(其中 xix_i 是一个二进制数,这一位是 11 代表可以治好)的病,产生 yiy_i(同 xix_i)的副作用。
那么问题来了:末状态 vv 是什么呢?
tt 的反状态为:tt 二进制下所有为 11 的位变为 0000 的位变为 11。所以 tt 的反状态 u=(2n1)tu=(2^n-1) \oplus t
那么 xix_i 的反状态 xxixx_i 就代表吃下药 ii 之后无法治好的病。那么原先得的病,和无法治好的病取个并,就可以得到吃下药 ii 产生副作用之前可以得到的病了。
至于副作用,与刚才的副作用之前的值或一下就行。这个理解起来很容易:只要这一个药可以产生,或者之前就得了,就会患。
然后枚举初状态 uu,枚举药,按照上面算出末状态 vv,然后跑最短路就行。

Code

CPP
#include<bits/stdc++.h>
using namespace std;
const int N=10;
int get(string s){
    int res=0,t=1;
    for(int i=0;i<s.length();i++){
        res=res+t*(s[i]=='1');
        t<<=1;
    }
    return res;
}
int n,m,dis[1<<N],vis[1<<N];
string tmp;
struct node{
    int x,y,t;
}a[1005];
void solve(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<(1<<n);i++){
        dis[i]=0x3f3f3f3f;
        vis[i]=0;
    }
    cin>>tmp;
    dis[get(tmp)]=0;
    for(int i=1;i<=m;i++){
        cin>>a[i].t;
        cin>>tmp;
        a[i].x=get(tmp);
        cin>>tmp;
        a[i].y=get(tmp);
    }
    while(1){
        int u=-1;
        for(int i=0;i<(1<<n);i++){
            if(vis[i]||dis[i]==0x3f3f3f3f)continue;
            if(u==-1||dis[i]<dis[u]){
                u=i;
            }
        }
        if(u==-1)break;
        vis[u]=1;
        for(int i=1;i<=m;i++){
            int w=a[i].t;
            int v=(u&(((1<<n)-1)^a[i].x))|a[i].y;
            dis[v]=min(dis[v],dis[u]+w);
        }  
    }
    cout<<(dis[0]==0x3f3f3f3f ? -1 : dis[0])<<endl;
}
int main(){
    int T;cin>>T;
    while(T--)solve();
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...