图论 - 某进制分组 - P5304 旅行者
P5304旅行者
: 多源多汇最短路,二进制分组
:非常好二进制分组,让我的大脑旋转
题意简述
给定
First. 怎么求多源多汇最短路
solution.1
超级源点和超级汇点,超级源点以
solution.2
对于 dijkstra 算法,直接把所有源点初始放进
But,这道题的起点和终点是不固定的!
所以第一种做法先暂不考虑。
Second. 怎么分起点终点
*MikeZ = & shuffle
直接 shuffle,随机分组!
-- by MikeZ
很不幸的是,这题没有很多时间让你反复跑随机化来获得正确答案,正确率不高。
二进制分组
对于每个标记的节点
Code
const int N = 2e5 + 10;
int n, m, k;
vector< pi > G[N];
ll dis[N];
bool vis[N];
int li[N];
ll dijkstra (int pos, int val) { // pos 表示 二进制的第几位,val表示是1为S集还是 0 为 S 集
priority_queue<pi, vector<pi>, greater<pi> > q;
memset(dis, 0x3f, sizeof dis);
memset(vis, 0, sizeof vis);
for (int i = 1; i <= k; i ++) {
int x = li[i];
if(((x >> (pos - 1)) & 1) == val) {
dis[x] = 0;
q.push({0, x});
}
}
while(!q.empty()) {
int u = q.top().second;
q.pop();
if(vis[u]) continue;
vis[u] = 1;
for (auto e : G[u]) {
int v = e.first, w = e.second;
if(dis[u] + w < dis[v]) {
dis[v] = dis[u] + w;
q.push({dis[v], v});
}
}
}
ll minn = 0x3f3f3f3f3f3f3f3f;
for (int i = 1; i <= k; i ++) {
int x = li[i];
if(((x >> (pos - 1)) & 1) != val) {
minn = min(dis[x], minn);
}
}
return minn;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while(t --) {
cin >> n >> m;
for (int i = 1; i <= n; i ++) G[i].clear();
for (int i = 1; i <= m; i ++) {
int u, v, w;
cin >> u >> v >> w;
G[u].push_back({v, w});
}
cin >> k;
for (int i = 1; i <= k; i ++) cin >> li[i];
ll ans = 0x3f3f3f3f3f3f3f3f;
for (int i = 0; i < 24; i ++) { // 枚举二进制位数
ans = min(ans, dijkstra(i, 0));
ans = min(ans, dijkstra(i, 1));
}
if(ans == 0x3f3f3f3f3f3f3f3f) cout << -1 << '\n';
else cout << ans << '\n';
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下