题意:给出n个点和m条有向边(有向边!!!!我还以为是无向查了半天),然后给出K个点,问这k个点中最近的两点的距离

思路:比赛时以为有询问,就直接丢了,然后这题感觉思路很棒,加入把所有点分成起点和终点两部分,然后加个S点和T点与他们

的距离为0,然后跑最短路就可以了,但是这样有可能最近的两个点都在起点或者都在终点,那么就不一定是最短的,所以就有个二进制分组。

考虑每个点的编号的二进制表示,那么对于任何两个点,他们至少有一位二进制不同,那么我们通过枚举二进制的位,当前位为1的作为起点集合,

当前位为2的作为终点集合,通过这样分组,我们就可以确定至少有一次分组任意两点分别在起点和终点。

复杂度O(20*nlogm)

代码:

/** @xigua */
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <cstring>
#include <queue>
#include <set>
#include <string>
#include <map>
#include <climits>
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
const int INF = 1e8 + 5;
const ll inf = 1e15 + 5;
const db eps = 1e-5;
int cnt, head[maxn]; ll dis[maxn];
struct Edge {
int v, next; ll w; //记住这里改顺序下面push进队一定要改!
bool operator < (const Edge &rhs) const {
return w > rhs.w;
}
} e[maxn<<2]; void add(int u, int v, int co) {
e[cnt].v = v;
e[cnt].w = co;
e[cnt].next = head[u];
head[u] = cnt++;
} void init() {
cnt = 0;
memset(head, -1, sizeof(head));
} void dij(int s, int len) {
priority_queue<Edge> pq;
for (int i = 1; i <= len; i++)
dis[i] = inf;
bool vis[maxn] = {0};
dis[s] = 0;
pq.push((Edge){s, 0, 0});
while (!pq.empty()) {
Edge tmp = pq.top(); pq.pop();
if (vis[tmp.v]) continue;
vis[tmp.v] = 1;
for (int i = head[tmp.v]; ~i; i = e[i].next) {
Edge u = e[i];
if (dis[u.v] > dis[tmp.v] + u.w) {
dis[u.v] = dis[tmp.v] + u.w;
pq.push((Edge){u.v, 0, dis[u.v]});
}
}
}
}
int a[maxn];
int u[maxn], v[maxn], w[maxn]; void solve() {
int n, m; cin >> n >> m;
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", u + i, v + i, w + i);
}
int k; cin >> k;
for (int i = 1; i <= k; i++) {
scanf("%d", a + i);
}
ll ans = inf;
for (int i = 0; i < 20; i++) {
init();
for (int j = 1; j <= m; j++) {
add(u[j], v[j], w[j]);
// add(v[j], u[j], w[j]);
}
for (int j = 1; j <= k; j++) {
if ((1<<i) & j) {
add(0, a[j], 0);
}
else {
add(a[j], n+1, 0);
}
}
dij(0, n + 10);
ans = min(ans, dis[n+1]);
init();
for (int j = 1; j <= m; j++) {
add(u[j], v[j], w[j]);
// add(v[j], u[j], w[j]);
}
for (int j = 1; j <= k; j++) {
if (((1<<i) & j) == 0) {
add(0, a[j], 0);
}
else {
add(a[j], n+1, 0);
}
}
dij(0, n + 10);
ans = min(ans, dis[n+1]);
}
cout << ans << endl;
} int main() {
int t = 1, cas = 1;
// freopen("in.txt", "r", stdin);
// freopen("in.txt", "w", stdout);
// init();
scanf("%d", &t);
while(t--) {
printf("Case #%d: ", cas++);
solve();
}
return 0;
}

  

HDU 6166 Senior Pan(多校第九场 二进制分组最短路)的更多相关文章

  1. hdu 6166 Senior Pan

    http://acm.hdu.edu.cn/showproblem.php?pid=6166 题意: 给出一张无向图,给定k个特殊点 求这k个特殊点两两之间的最短路 二进制分组 枚举一位二进制位 这一 ...

  2. HDU 6166 Senior Pan (最短路变形)

    题目链接 Problem Description Senior Pan fails in his discrete math exam again. So he asks Master ZKC to ...

  3. HDU 6166.Senior Pan()-最短路(Dijkstra添加超源点、超汇点)+二进制划分集合 (2017 Multi-University Training Contest - Team 9 1006)

    学长好久之前讲的,本来好久好久之前就要写题解的,一直都没写,懒死_(:з」∠)_ Senior Pan Time Limit: 12000/6000 MS (Java/Others)    Memor ...

  4. HDU 6166 Senior Pan 二进制分组 + 迪杰斯特拉算法

    Senior Pan Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Probl ...

  5. 2017多校第9场 HDU 6166 Senior Pan 堆优化Dij

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6166 题意:给你一个有向图,然后给你k个点,求其中一个点到另一个点的距离的最小值. 解法:枚举二进制位 ...

  6. HDU 6166 Senior Pan(k点中最小两点间距离)题解

    题意:n个点,m条有向边,指定k个点,问你其中最近的两点距离为多少 思路:这题的思路很巧妙,如果我们直接枚举两点做最短路那就要做C(k,2)次.但是我们换个思路,我们把k个点按照二进制每一位的0和1分 ...

  7. HDU 6166 Senior Pan(二进制分组+最短路)

    题意 给出一个\(n\)个点\(m\)条边的有向图\((n,m<=100000)\),从中选择\(k\)个点\((k<=n)\),问这k个点两两之间的最短路最小值是多少? 思路 直接的想法 ...

  8. 2018 Multi-University Training Contest 9 杭电多校第九场 (有坑待补)

    咕咕咕了太久  多校博客直接从第三场跳到了第九场orz 见谅见谅(会补的!) 明明最后看下来是dp场 但是硬生生被我们做成了组合数专场…… 听说jls把我们用组合数做的题都用dp来了遍 这里只放了用组 ...

  9. hdu 6169 Senior PanⅡ Miller_Rabin素数测试+容斥

    Senior PanⅡ Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others) Pr ...

随机推荐

  1. Lua 5.1.1 源代码阅读笔记

    http://blog.csdn.net/hamenny/article/details/4506130

  2. throw UnsupportedOperationException

    package org.usc.action; import java.util.ArrayList; import java.util.Arrays; import java.util.List; ...

  3. hdoj5875【二分+RMQ】

    全部从我大哥那里学习得来.. 一开始硬着头皮就是根据思路上线段树,明知是T还要写(因为线段树还不是很熟,趁机练一发) 后来果然T了,然后就去学了一发RMQ的ST算法,查询是O(1). ST算法主要: ...

  4. std::thread 在DLLMain 中会发生死锁 std::thread cause deadlock in DLLMain

    注意不要再DLLMain中使用 std::thread 否则会发生死锁. 但是可以使用 _beginthreadex (此函数可以使用lambda) 或者直接使用windows的底层函数: Creat ...

  5. IT兄弟连 JavaWeb教程 JSTL常用标签

    1.条件标签 条件标签能够实现Java语言中的if语句以及if-else语句的功能,它包括以下几种: <c:if>:用于实现Java语言中的if语句的功能. <c:choose> ...

  6. #10:wannanewtry——6

    HDU3401,列完转移方程拆分一下,正着.反着跑优先队列优化代表买或卖.初始化不大会搞…… #include <bits/stdc++.h> using namespace std; c ...

  7. 转 错误:ORA-28002/ORA-65162 : the password will expire within 7 days 解决方法

    今天在使用sqlplus时出现 =============================================== ERROR:ORA-28002: the password will e ...

  8. HDU 1028 Ignatius and the Princess III dp整数划分

    http://acm.hdu.edu.cn/showproblem.php?pid=1028 dp[i][j]表示数值为i,然后最小拆分的那个数是j的时候的总和. 1 = 1 2 = 1 + 1 . ...

  9. MDX查询语句

    另:15个经典的MDX查询语句 另:http://www.cnblogs.com/biwork/p/3437959.html 1.排名+排序+量值过滤: WITH member [Measures]. ...

  10. Windows7获取、更换桌面背景,C#

    使用的API原型是 BOOL SystemParametersinfo(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinlni); 在C#中定义如下 ...