P4366 [Code+#4] 最短路 - 洛谷
题目:
思路:
其实是找性质
本题我们首先可以想到的就是建图然后跑最短路,但是数据给的很大,如果直接暴力建图显然不行,考虑一些特殊情况需要建图
考虑 1 -> 7 这个例子
我们一种走法是直接从 1->7,那么二进制下就是 001 -> 111,花费就是 6 * c
另一种走法就是考虑走中间节点,具体的从 001 -> 011 -> 111,花费一样也是 6 * c
可以看出,只要两个数有超过一位不同,那么就能通过中间节点走到终点
具体的,我们每个数都建一条和自己有一位不同的边,那么其连接的点就是 i ^ ,即只有一位不同,这个位可以是 32 位中的任意一位,所以价值就是 c * (i ^ (i ^
)) = c *
所以就从 n*n 变成了 n*logn 的建图了,顺利解决
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include <iomanip>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <utility>
#include <array>
#include <tuple>
using namespace std;
#define int long long
#define yes cout << "YES" << endl
#define no cout << "NO" << endl
vector<vector<pair<int,int>>> g(100005);
int n, m, c;
int dis[100005];
int s, e;
void Init()
{
for (int i = 0; i <= n; i++)
{
for (int j = 1; j <= n; j <<= 1)
{
if ((i ^ j) > n)
continue;
g[i].push_back({ i ^ j, j * c });
}
}
}
void fuc()
{
dis[s] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
pq.push({ 0,s });
while (!pq.empty())
{
auto t = pq.top();
pq.pop();
if (t.second == e || dis[t.second] < t.first)
{
continue;
}
for (auto & son : g[t.second])
{
int v = son.first;
int cost = son.second;
if (dis[v] > t.first + cost)
{
dis[v] = t.first + cost;
pq.push({ t.first + cost ,v });
}
}
}
}
void solve()
{
cin >> n >> m >> c;
for (int i = 0; i < m; i++)
{
int u, v, c;
cin >> u >> v >> c;
g[u].push_back({ v, c });
}
cin >> s >> e;
Init();
memset(dis, 0x3f, sizeof dis);
fuc();
cout << dis[e] << endl;
}
signed main()
{
//cin.tie(0)->sync_with_stdio(false);
int t = 1;
//cin >> t;
while (t--)
{
solve();
}
return 0;
}