A county consists of n cities (labeled 1, 2, …, n) connected by some bidirectional roads. Each road connects a pair of distinct cities. A robot company has built maintenance points in some cities. Now, they need your help to write a program to query the nearest maintenance point to a specific city.
InputThere will be at most 200 test cases. Each case begins with four integers n, m, s, q(2 ≤ n ≤ 104, 1 ≤ m ≤ 5 × 104, 1 ≤ s ≤ min{n, 1000},1 ≤ q ≤ min{n, 1000}), the number of cities, the number of roads, the number of cities which have maintenance points and the number of queries. Then m lines contain the descriptions of roads. Each of them contains three integers ui, vi, wi(1 ≤ ui, vi ≤ n, ui ≠ vi, 1 ≤ wi ≤ 1000), denoting there is a road of length wi which connects city ui and vi. The next line contains s integers, denoting the cities which have maintenance points. Then qlines contain the descriptions of queries. Each of them contains one integer denoting a specific city. The size of the whole input file does not exceed 6MB.
OutputFor each query, print the nearest city which has a maintenance point. If there are multiple such cities, print all of them in increasing order separated by a single space. It is guaranteed that there will be at least one such city.
Sample Input4 4 2 3 1 2 1 2 3 2 2 4 1 4 3 2 1 3 3 2 4Sample Output
3 1 1 3Hint
题意:输出n,m,s,q,n为n个点,m为m条边,s为s个特殊点,q为q次询问,q每次询问一个点,输出离这个点最近的特殊点,要是有多个就按从小到大顺序输出;
思路,总不能来s次dijstar吧, 因为找的是离这个点最近的特殊点,我们可以设一个超级源点 0 ,再从超级源点到每一个特殊点连上一条边,边权为0,之间从超级源点 0开始 搜就行了,在这用了优先队列优化的dijstar,用到了c++中的容器bitset,记录到这点的特殊点,比bitset,二进制运算,有点类似于状压的感觉;
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#include<bitset>
#include<queue>
#define Max 10005
#define INF 0x3f3f3f3f
bitset<1005>ans[Max];
struct node
{
int x,d;
bool operator < (const node a) const
{
return a.d < d;
}
};
struct edge
{
int end,d;
}stu[Max*10+1000]; // 数组大小,因为边是双向的,开二倍;
int frist[Max],next1[Max*10+1000];
int n,m,s,p;
bool vis[Max]; // 标记特殊点
int dis[Max]; // 超级源点0到这一点的最短距离,也就是特殊点到这一点的最短距离;
bool book[Max];
int ss[1005]; //存特殊点
int sum;
void add_edge(int x,int y,int d)
{
stu[sum].end = y;
stu[sum].d = d;
next1[sum++] = frist[x];
frist[x] = sum - 1;
}
void init()
{
memset(frist,-1,sizeof(frist));
memset(vis,false,sizeof(vis));
for(int i = 0;i<=n;i++)
ans[i].reset();
}
void dijstar(int st)
{
memset(dis,INF,sizeof(dis));
memset(book,false,sizeof(book));
dis[st] = 0;
priority_queue<node >q;
node star;
star.x = st;
star.d = 0;
q.push(star);
while(!q.empty())
{
star = q.top();
q.pop();
int t = star.x;
if(book[t]) continue; // 气死了,刚开始上面 让 t==frist[star.x],下面标记t了,标记成边了,
// 怎么也没找到错,哎,邻接表用的不熟练;
book[t] = true;
for(int i = frist[t];i!=-1;i = next1[i])
{
if(dis[stu[i].end] > dis[star.x] + stu[i].d)
{
dis[stu[i].end] = dis[star.x] + stu[i].d;
node end;
end.x = stu[i].end;
end.d = dis[stu[i].end];
q.push(end);
if(vis[stu[i].end]) continue; // 如果第一次到到这个点时的距离为6,那么第二次为5的话,
// 那么 6 就不用 重复找最短路了
ans[stu[i].end].reset(); // ans[i].reset(),把容器ans[i]中的二进制全部变为0;
/*for(int j = 0;j<s;j++)
{
if(ans[star.x][j]) // ans[i][j],判断bitset容器ans[i] 在j这个位置上的二进制是不是1;
ans[stu[i].end][j] = 1;
}*/
ans[stu[i].end] = ans[star.x]; // 大于,直接覆盖;
}
else if(dis[stu[i].end] == dis[star.x] + stu[i].d)
{
/*for(int j = 0;j<s;j++)
{
if(ans[stu[i].star][j])
ans[stu[i].end][j] = 1;
}*/
ans[stu[i].end] |= ans[star.x]; // 相等的情况就有多个 或上;
}
}
}
// 于spfa 的区别,spfa 是用的队列,这个是优先队列, spfa判断这个点要是在队列中,就只更新到这个点的距离
// 不加入队列,而这个堆优化的dijstar必须要加入队列,这个按到这点的距离排序的,第一次是到这个点的距离6,
// 第二次 到这个点距离是5,那么一定加入队列;每一次取得都是距离起点最近的点,所以不没有出队列时,取消标记;
// 而 spfa 出队列时要取消标记,因为取得不是离起点最近的点,spfa和dijstar更新的都是相邻边,spfa,第一次从这一点更新时
// 这一点到起点的距离是6,更新了一次,从其他点到到这个点的距离是5,你要是出队列时,没有取消标记的话,那么就进不了队列了
// 没法更新成最短的距离了,所以,spfa出队列时要取消标记;
}
int main()
{
int i,j;
while(~scanf("%d%d%d%d",&n,&m,&s,&p))
{
init();
int x,y,d;
sum = 0;
for(i = 0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&d);
add_edge(x,y,d);
add_edge(y,x,d);
}
for(i = 0;i < s ;i++)
scanf("%d",&ss[i]);
sort(ss,ss+s);
for(i = 0;i<s;i++)
{
vis[ss[i]] = true;
add_edge(0,ss[i],0);
ans[ss[i]][i] = 1;
}
dijstar(0);
for(i = 0;i<p;i++)
{
scanf("%d",&x);
int flag = 0;
for(j = 0;j < s;j++)
{
if(ans[x].test(j)) // 判断j这一位上是不是 1;
{
if(flag) printf(" ");
printf("%d",ss[j]);
flag = 1;
}
}
printf("\n");
}
}
return 0;
}