zoukankan      html  css  js  c++  java
  • 牛客练习赛67 牛妹游历城市 题解(最短路+虚点)

    题目链接

    题目大意

    给你n(n<=1e5)个点,每个点有一个权值a[i],要你求从1到n的最短路

    a[i]∩a[j]=0;dis[i][j]=0

    a[i]∩a[j]!=0;dis[i][j]=lowbit(a[i]∩a[j])

    题目思路

    首先吐槽一下\(a[i]<2^{32}\) 这是ll级别的,\(int<2^{31}\)真毒瘤

    这个题目利用了建虚点,对32个二进制位建立32个虚点,对于每个a[i],如果该二进制位j为1,那么连边权值为 1 << j。(注意虚点到该点的距离为0)

    然后跑一个dij即可

    你可能会问那这里跑的不就是所有的a[i]&a[j]的二进制位了嘛,而不是那个lowbit的那个二进制嘛

    确实,但是你会发现这个是求最短路,那么最短路跑的必然是那个lowbit的那个二进制位

    代码

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<string>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<unordered_map>
    #define fi first
    #define se second
    #define debug printf(" I am here\n");
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<ll,int> pii;
    const ll INF=0x3f3f3f3f3f3f3f3f;
    const int maxn=1e5+50,inf=0x3f3f3f3f,mod=998244353;
    const double eps=1e-10;
    int n;
    ll a[maxn];//int 2^31-1,要ll
    int head[maxn],cnt;
    ll dis[maxn];
    struct edge{
        int to,next;
        ll w;
    }e[maxn<<6];
    void add(int u,int v,ll w){
        e[++cnt]={v,head[u],w};
        head[u]=cnt;
    }
    void init(){
        cnt=0;
        memset(head,0,sizeof(head));
    }
    void dij(int x){
    	priority_queue<pii,vector<pii>,greater<pii> > que;
    	memset(dis,0x3f,sizeof(dis));
    	dis[x]=0;
    	que.push({0,x});
    	while(!que.empty()){
    		int len=que.top().first;
    		int pos=que.top().second;
    		que.pop();
    		if(len<=dis[pos]){
    			for(int i=head[pos];i;i=e[i].next){
    				if(dis[e[i].to]>dis[pos]+e[i].w){
    					dis[e[i].to]=dis[pos]+e[i].w;
    					que.push({dis[e[i].to],e[i].to});//一定注意是len为fi
    				}
    			}
    		}
    	}
    }
    signed main(){
        int _;scanf("%d",&_);
        while(_--){
            scanf("%d",&n);
            init();
            for(int i=1;i<=n;i++){
                scanf("%lld",&a[i]);
                for(int j=0;j<=31;j++){
                    if(a[i]&(1ll<<j)){
                        add(i,n+j+1,(1ll<<j));//n+j+1为虚点
                        add(n+j+1,i,0);
                    }
                }
            }
            dij(1);
            if(dis[n]==INF){
                printf("Impossible\n");
            }else{
                printf("%lld\n",dis[n]);
            }
        }
        return 0;
    }
    
    
    不摆烂了,写题
  • 相关阅读:
    cmder 基本配置和使用
    apache开启.htaccess及.htaccess的使用方法
    PHP 伪静态规则写法RewriteRule-htaccess详细语法使用
    Oracle创建分区表
    Oracle基础知识
    SQLPLUS
    linux上使用docker安装oracle
    使用IDEA创建可执行jar
    Hyper-V-问题整理
    spring的容器管理
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/13738014.html
Copyright © 2011-2022 走看看