牛客练习赛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

备注:
数据保证\(1\le T\le 5, 1\le n\le 10^5, 1\le 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\n");
		else printf("%lld\n",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);
			}
		}
	}
}
posted @ 2020-08-15 11:24  lonely_wind  阅读(178)  评论(0编辑  收藏  举报