题目链接: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);
}
}
}
}