题目链接
一.题目内容
给一个双向图,点为城市,边为路,有几个特殊的城市设有维修点,问离某个点最近的维修点有哪些
样例解释
离3最近的就是3,离2最近的是1,离4最近的有1和3
二.解题思路
题目所给数据太大,若求所有维修点的单源最短路则要最多1000次dijkstra,所以只能把所有维修点放入堆中跑一次最短路,这时dis数组记录不是从某点到某点的最短路长度,而是某个点离最近维修点的最短路长度。
那么问题来了,如果把所有维修点都一起跑最短路,那么怎么判断该最短路是来源于哪个维修点呢?
这时就有个骚操作,用bitset来存储当前点的最短路是来源于哪个维修点。所给数据中维修点最多1000次,所以创一个1000大小的bitset,每一位代表着每一个维修点,值若为1则代表当前点的最短路来源于该维修点。
比如离维修点最近的当然就是它本身,所以维修点的bitset中它自身所对应的bitset中的位置就是1。
在跑dijkstra时,若从 u 到达 v,
①所得新路径长度<dis[v]时,则更新dis[v],并将 v 所对应的bitset设为u所对应得bitset,因为v当前的最短路径来源于u,而u的最短路径来源于它的bitset里面值为1的维修点,所以v的最短路径现在来源于u的bitset里面值为1的维修点
② 所得新路径长度==dis[v]时,则将 v 的bitset与 u 的bitset用 '| '操作合并,道理同上,只是 v 的最短路同时也来源于 v 本身的bitset中值为1的维修点。
最后只需循环一遍所求的点的bitset,值为1的就代表是最近的维修点
三.解题代码
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define rrep(i, l, r) for (int i = l; i >= r; --i)
#define int long long
int dir[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
const int N = 1e4 + 10, M = 1e9 + 7;
//-----------//
bitset<N>msk[N]; // 每个点对应一个bitset
int dis[N],ss[N];
struct node {
int v,w;
friend bool operator < (const node&t1,const node&t2) {
return t1.w>t2.w;
}
};
int n,m,s,q;
vector<node>a[N];
void dj() {
priority_queue<node>q;
rep(i,1,n) {
msk[i].reset();
dis[i]=LLONG_MAX;
}
rep(i,1,s) {
q.push(node{ss[i],0}); //将所有维修点放入堆中
dis[ss[i]]=0; //维修点最短路径为0
msk[ss[i]][i]=1; //每个维修点最开始的bitset中值为1的就是它们本身
}
while(q.size()) {
node cur=q.top();
q.pop();
if(dis[cur.v]<cur.w) continue;
for(auto i:a[cur.v]) {
int d=cur.w+i.w;
if(dis[i.v]>d) {
dis[i.v]=d;
msk[i.v]=msk[cur.v]; //有新最短路径时将i.v的bitset用cur.v覆盖
q.push(node{i.v,d});
} else if(dis[i.v]==d) msk[i.v]|=msk[cur.v]; // 路径相同时,则合并
}
}
}
signed main() {
while(~scanf("%lld%lld%lld%lld",&n,&m,&s,&q)) {
rep(i,1,n) a[i].clear();
while(m--) {
int x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
a[x].push_back(node{y,z});
a[y].push_back(node{x,z});
}
rep(i,1,s) scanf("%lld",&ss[i]);
sort(ss+1,ss+s+1); // 先排序,因为最后输出要按从从小大大输出
dj();
while(q--) {
int x;
scanf("%lld",&x);
vector<int>ans;
rep(i,1,s) {
if(msk[x][i]) ans.push_back(ss[i]); //若为1,则将维修点的点号放入答案数组
}
for(auto i:ans) printf("%lld ",i);
puts("");
}
}
}