• 牛客练习赛67 E-牛妹游历城市(拆位最短路)


    题目链接:https://ac.nowcoder.com/acm/contest/6885/E
    CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/108019842

    题目描述

    最近,牛妹天天宅在家里,真是憋死人了。他决定出去旅游。
    牛妹现在正在1号点(自己家里),他决定前往n号点(牛妹想去的地方),中途可以多次经过1~n号点。
    现在,已知每个点都有个权值(a_i),如果(a_i & a_j ≠0),则i号点和j号点之间连有一条双向边,权值为(lowbit(a_i & a_j))
    他想要最小化自己的行走距离,但是他计算不出来qaq。相信全牛客最聪明的你一定会吧!
    Tips:
    (&)是位运算中and的意思,lowbit(n)的值是最大的(2^x),满足(2^x | n)
    例如(lowbit(5)=lowbit((101)_2)=1, lowbit(8)=lowbit((1000)_2)=8)

    输入描述:
    本题有多组数据。
    第一行,输入一个数T,表示数据组数。
    接下来2*T行,先输入一个数n,再输入n个数,第i个数表示(a_i)

    输出描述:
    对于每组数据,输出最小的行走距离。
    如果无法从1号点到达n号点,则输出“Impossible”(不含引号)。

    输入
    2
    6
    2 3 5 8 13 21
    12
    1 2 3 4 5 6 7 8 9 10 11 12
    输出
    3
    5

    输入
    5
    3
    1 2 3
    4
    177 188 199 211
    2
    1 2
    4
    1 1 1 1
    5
    1 2 4 8 16

    输出
    1
    1
    Impossible
    1
    Impossible

    备注:
    数据保证(1le Tle 5, 1le nle 10^5, 1le a_i < 2^{32})

    emmm,这个肯定不能直接暴力建边的,所以我们考虑优化,我们对于二进制下的每一位建立一个超级点,然后对每个点判断它的该位是否存在,如果存在的话我们将其与对应的超级点建边,其边权设为(2^i),但需要注意的是这样跑出来的距离是实际距离的两倍,所以最后我们还需要除以2。

    以下是AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int mac = 4e6 + 10;
    const ll inf = 2e18 + 10;
    struct node
    {
    	int to, next;
    	ll w;
    };
    struct node1
    {
    	int id;
    	ll d;
    	bool operator < (const node1& a)const {
    		return d > a.d;
    	}
    };
    node eg[mac<<1];
    int num = 0, head[mac], vis[mac];
    ll dis[mac],a[mac];
    void add(int u, int v, ll w);
    void Dij(int s);
    int main()
    {
    	int t;
    	scanf ("%d",&t);
    	while (t--){
    		int n;
    		scanf ("%d",&n);
    		num=0;
    		memset(head,-1,sizeof head);
    		for (int i=1; i<=n; i++){
    			scanf ("%lld",&a[i]);
    			dis[i]=inf;
    		}
    		dis[0]=inf;
    		for (int i=n+1; i<=2*n+100; i++) dis[i]=inf;
    		for (int i=0; i<=31; i++){
    			for (int j=1; j<=n; j++){
    				if ((a[j]>>i)&1){
    					add(j,n+i+1,1LL<<i);
    					add(n+i+1,j,1LL<<i);
    				}
    			}
    		}
    		Dij(1);
    		if (dis[n]>=inf) printf("Impossible
    ");
    		else printf("%lld
    ",dis[n]/2);
    	}
    	return 0;
    }
    void add(int u, int v, ll w)
    {
    	eg[++num].to = v; eg[num].w = w; eg[num].next = head[u];
    	head[u] = num;
    }
    void Dij(int s)
    {
    	memset(vis, 0, sizeof(vis));
    	dis[s] = 0;
    	priority_queue<node1>q;
    	node1 f;
    	f.id = s; f.d = 0;
    	q.push(f);
    	while (!q.empty()) {
    		node1 now = q.top();
    		q.pop();
    		int u = now.id;
    		if (vis[u]) continue;
    		vis[u] = 1;
    		for (int i = head[u]; i != -1; i = eg[i].next) {
    			int v = eg[i].to;
    			ll w = eg[i].w;
    			if (dis[v] > now.d + w) {
    				dis[v] = now.d + w;
    				node1 f;
    				f.id = v; f.d = dis[v];
    				q.push(f);
    			}
    		}
    	}
    }
    
  • 相关阅读:
    事务与锁的一些总结
    NYOJ 73
    NYOJ 456
    Sleep函数
    NYOJ 488(素数环)
    NYOJ 308
    NYOJ 27
    NYOJ 325
    NYOJ 138
    求两个或N个数的最大公约数(gcd)和最小公倍数(lcm)的较优算法
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13507992.html
Copyright © 2020-2023  润新知