题目大意:
给你n个数. 两个数之间有一条 a i + a j a_i+a_j ai+aj的边,当 a i & a j ≠ 0 a_i\&a_j \neq 0 ai&aj=0.问从1开始的最短路.
题目思路:
拆位来看,所有 a x & 2 k ≠ 0 a_x\&2^k \neq 0 ax&2k=0的数两两之间都有边.拉一个 虚 点 虚点 虚点连向他们。开31个虚点跑最短路即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;
ll a[maxn];
int bk[maxn];
ll dist[maxn];
struct Node{
ll id , dist;
bool operator < (const Node & a) const {
return dist > a.dist;
}
};
vector<pair<int,ll>> e[maxn + 50];
int main()
{
ios::sync_with_stdio(false);
int n; cin >> n;
for (int i = 1 ; i <= n ; i++) {
cin >> a[i];
// 高效建图
for (int j = 0 ; j <= 30 ; j++){
if (a[i] & (1 << j)){
e[i].pb({n + j + 1 , a[i]});
e[n + j + 1].pb({i , a[i]});
}
}
}
memset(dist , -1 , sizeof dist);
priority_queue<Node> q;
q.push({1 , 0});
dist[1] = 0;
while (q.size()){
Node tmp = q.top();q.pop();
int id = tmp.id;
if (bk[id]) continue;
bk[id] = 1;
for (auto g : e[id]){
ll v = g.first , w = g.second;
if (dist[v] == -1 || dist[v] > dist[id] + w){
dist[v] = dist[id] + w;
q.push({v , dist[v]});
}
}
}
for (int i = 1 ; i <= n ; i++){
cout << dist[i] << " ";
}
cout << endl;
return 0;
}