zoukankan      html  css  js  c++  java
  • E Magical Ornament 题解(图论+状压dp)

    题目链接

    题目大意

    给你n个宝石,有m对(a[i],b[i])关系,以及k种必须出现的宝石

    你要保证出现k种必须出现的宝石(每种宝石>=1即可),且出现的宝石要满足m对关系的两两相邻

    求最少的宝石数,不满足则直接输出-1

    \(1<=n<=1e5\;\;0<=m<=1e5\;\;1<=k<=17\)

    题目思路

    首先相邻则可以当作建边

    然后用bfs预处理这k的点的两两直接的距离

    然后用状压dp转移

    \(dp[sta][last]\) 表示当前状态为sta,且现在在last点

    用状压最朴素的转移即可

    代码

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define debug cout<<"I AM HERE"<<endl;
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+5,inf=0x3f3f3f3f,mod=998244353;
    const int eps=1e-6;
    int n,m,k;
    int head[maxn],cnt;
    int c[maxn];
    int dis[20][20],len[maxn];
    int dp[1<<17][20];
    struct edge{
        int to,next;
    }e[maxn<<1];
    void add(int u,int v){
        e[++cnt]={v,head[u]};
        head[u]=cnt;
    }
    void bfs(int x){
        memset(len,0x3f,sizeof(len));
        len[x]=0;
        queue<int> que;
        que.push(x);
        while(!que.empty()){
            int x=que.front();
            que.pop();
            for(int i=head[x];i;i=e[i].next){
                if(len[e[i].to]!=inf) continue;
                len[e[i].to]=len[x]+1;
                que.push(e[i].to);
            }
        }
    }
    signed main(){
        scanf("%d%d",&n,&m);
        for(int i=1,u,v;i<=m;i++){
            scanf("%d%d",&u,&v);
            add(u,v),add(v,u);
        }
        scanf("%d",&k);
        for(int i=1;i<=k;i++){
            scanf("%d",&c[i]);
        }
        for(int i=1;i<=k;i++){
            bfs(c[i]);
            for(int j=1;j<=k;j++){
                dis[i][j]=len[c[j]];
            }
        }
        memset(dp,0x3f,sizeof(dp));
        for(int i=1;i<=k;i++){ //预处理
            dp[1<<(i-1)][i]=1;
        }
        for(int sta=0;sta<(1<<k);sta++){
            for(int last=1;last<=k;last++){
                if(!(sta&(1<<(last-1)))||dp[sta][last]==inf) continue; //没有交集
                for(int nxt=1;nxt<=k;nxt++){
                    if(sta&(1<<(nxt-1))) continue; //已经有交集了
                    dp[sta|(1<<(nxt-1))][nxt]=min(dp[sta|(1<<(nxt-1))][nxt],dp[sta][last]+dis[last][nxt]);
                }
            }
        }
        int ans=inf;
        for(int i=1;i<=k;i++){
            ans=min(ans,dp[(1<<k)-1][i]);
        }
        if(ans==inf) ans=-1;
        printf("%d\n",ans);
        return 0;
    }
    
    
    不摆烂了,写题
  • 相关阅读:
    C#中使用MATLAB
    各种插值法及效果图对比
    Visual Studio中你所不知道的智能感知
    C#中使用Surfer
    XCode中连接使用GitHub
    个人作业Week1
    个人作业Week3
    个人作业Week2
    第一次作业——subway
    执行ajax加载页面中的js总结
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/14352588.html
Copyright © 2011-2022 走看看