奇怪的最短路
Description
给定长度为 的数列 ,如果 (按位与),则在 之间存在一条长度为 的边,求 至所有点的最短路。
Input
第一行一个正整数 。 接下来一行 n 个整数 。
Output
输出一行 n 个整数,第 i 个为 1 到 i 的最短路长度。不能到达输出 。
Sample Input
5
1 5 6 7 8
Sample Output
0 6 17 8 -1
HINT
对于 的数据, 。
解题思路
本题关键在于建图,对于 看作 个节点,此外由于 ,所以 在二进制下最多有 位,看作 个节点,若 二进制值的第 位是 ,则对 和 建边,边权为 ,然后跑一次最短路即可。 PS:注意边的数量要开够
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 99;
inline int read()
{
char c = getchar();
int x = 0;
bool f = 0;
for (; !isdigit(c); c = getchar())
{
f ^= !(c ^ 45);
}
for (; isdigit(c); c = getchar())
{
x = (x << 1) + (x << 3) + (c ^ 48);
}
if (f)
{
x = -x;
}
return x;
}
inline void write(int x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9)
{
write(x / 10);
}
putchar(x % 10 + '0');
}
long long n, m;
array<long long, maxn> dis;
bool vis[maxn];
long long x[maxn];
struct edge
{
int to, w;
};
vector<edge> d[maxn];
struct node
{
long long i, dis;
bool operator<(const node tmp) const
{
return tmp.dis < dis;
}
};
void add(int a, int b, int w)
{
d[a].push_back({b, w});
}
void Dijkstra()
{
dis.fill(0x3f3f3f3f3f);
priority_queue<node> q;
dis[1] = 0;
q.push({1, 0});
while (!q.empty())
{
node tmp = q.top();
q.pop();
int t = tmp.i;
if (vis[t])
continue;
vis[t] = 1;
for (int i = 0; i < d[t].size(); i++)
{
if (dis[t] + d[t][i].w < dis[d[t][i].to])
{
dis[d[t][i].to] = dis[t] + d[t][i].w;
q.push({d[t][i].to, dis[d[t][i].to]});
}
}
}
}
signed main()
{
n = read();
for (int i = 1; i <= n; ++i)
{
x[i] = read();
for (int j = 0; j <= 30; j++)
if ((x[i] & (1 << j)) != 0)
add(i, n + j + 1, x[i]), add(n + j + 1, i, x[i]);
}
Dijkstra();
for (int i = 1; i <= n; ++i)
{
write((dis[i] == 0x3f3f3f3f3f ? -1 : dis[i]));
putchar(' ');
}
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122176