1690: Terrorists
时间限制: 5 Sec
内存限制: 128 MB
提交: 11
解决: 3
[ 提交][ 状态][ 讨论版]
题目描述
Terrorists! There are terrorists everywhere!!! I was shouting out loud after I had watched a few news
reports about terrorism acts that had happened around my neighborhoods. I started to think that hiding at
home wasn’t a good way to go.
I went to police stations and asked around if I could help them prevent these issues. The police
gave me pieces of information about terrorists’ plans. I ended up lying on my bed and figuring way to
utilize this information. That is why I come to you.
Our neighborhoods could be illustrated with intersections and roads. Terrorists usually meet up at
one intersection before moving to another intersection to perform an illegal act. The given information
tells us where they will meet and where they will go. Unfortunately, the certain schedules of those plans
are not available and too few policemen are available lately. So, the police will not be able to set up
efficient defenses to all of those acts. What they could do is set up surveillance cameras to all meet up
intersections. Once a meet up is detected, policemen will go to that meet up’s destination to catch the
terrorists. The policemen rarely accomplish it because they spend too long time travelling between places.
Because terrorists are smart, they always use shortest route to travel between intersections.
Because the policemen aren’t that smart, they need our help. For each terrorist plan, the police want us to
compute the shortest distance between the meet up place and the destination. If the distance is too short,
they will not spend their efforts for free.
输入
The first line of the input contains an integer T, the number of test sets (1 <= T <= 5).
Each test case consists of many lines. The first line contains 3 integers N, M, Q which are the
number of intersections, the number of roads, and the number of terrorists’ plans in respective order.
1 <= N <= 100 000, N - 1 <= M <= N + 50, 1 <= Q <= 50 000
Then the next M lines describe the roads in our neighborhoods. A road is described by 3
integers: U, V, D. Ui and Vi represent 2 ends of the road i. Di represents distance of that road.
1 <= Ui, Vi <= N, 1 <= Di <= 10 000. It is possible that many roads might exist between a pair of
intersection.
Finally the next Q lines are the terrorism plans. A plan j is described by 2 integers: Sj and Ej
which are the meet-up intersection and the destination intersection respectively. 1 <= Sj, Ej <= N.
输出
For each test set, print out “Case x:” where x is a case number beginning with 1, and then
followed by Q lines. For each terrorism plan, output the shortest distance between the meet-up
intersection and the destination of the plan.
样例输入
1
7 9 5
7 6 6114
5 3 5473
2 4 2601
5 4 8525
7 3 291
2 7 3363
1 6 399
6 4 4477
1 7 3075
6 3
4 4
3 1
2 3
7 3
样例输出
Case 1:
3765
0
3366
3654
291
题意:给出一幅图,和q个询问,每次输出两点之间的最短路
观察给出的数据发现边最多比n多50,暗示着可以通过某种暴力的手段.
先建一棵生成树,最多有50条左右非树边然后对于树上的点可以LCA搞定最近距离,对于剩下树边上的的每个点都跑一次SPFA,然后每次询问取LCA和非树边点到询问点距离和的最小值.这样单组询问的复杂度只有O(100+lgn).
#include <bits/stdc++.h>
using namespace std;
#define maxn 111111
#define maxm 211111
#define INF 1111111111
const int DEG = 20;
struct Edge
{
int to,next, w;
}edge[maxn*2];
int head[maxn],tot;
int n, m, q, root;
void add_edge(int u,int v, int w)
{
//cout << u << " " << v << endl;
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
int fa[maxn][DEG];//fa[i][j]表示结点i的第2^j个祖先
int deg[maxn];//深度数组
void BFS(int root)
{
queue<int>que;
deg[root] = 0;
fa[root][0] = root;
que.push(root);
while(!que.empty())
{
int tmp = que.front();
que.pop();
for(int i = 1;i < DEG;i++)
fa[tmp][i] = fa[fa[tmp][i-1]][i-1];
for(int i = head[tmp]; i != -1;i = edge[i].next)
{
int v = edge[i].to;
if(v == fa[tmp][0])continue;
deg[v] = deg[tmp] + 1;
fa[v][0] = tmp;
que.push(v);
}
}
}
int LCA(int u,int v)
{
if(deg[u] > deg[v])swap(u,v);
int hu = deg[u], hv = deg[v];
int tu = u, tv = v;
for(int det = hv-hu, i = 0; det ;det>>=1, i++)
if(det&1)
tv = fa[tv][i];
if(tu == tv)
return tu;
for(int i = DEG-1; i >= 0; i--)
{
if(fa[tu][i] == fa[tv][i])
continue;
tu = fa[tu][i];
tv = fa[tv][i];
}
return fa[tu][0];
}
bool flag[maxn];
int e[maxm][2], w[maxn];
bool is_edge[maxm];
int p[maxn];
#define find Find
int find (int x) {
return p[x] == x ? p[x] : p[x] = find (p[x]);
}
int d[maxn];
bool vis[maxn];
int dfs (int u, int deep) {//获取每个节点到根的距离
d[u] = deep;
vis[u] = 1;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (vis[v])
continue;
dfs (v, deep+edge[i].w);
}
}
void build () {//建一颗生成树
init ();
memset (is_edge, 0, sizeof is_edge);
for (int i = 1; i <= n; i++)
p[i] = i;
root = 1;
for (int i = 1; i <= m; i++) {
int u = e[i][0], v = e[i][1];
int p1 = find (u), p2 = find (v);
if (p1 != p2) {
p[p1] = p2;
is_edge[i] = 1;//加入树边
add_edge (u, v, w[i]);
add_edge (v, u, w[i]);
}
}
BFS (root);
memset (vis, 0, sizeof vis);
dfs (root, 0);
return ;
}
struct Edge2
{
int v;
int cost;
Edge2(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge2>E[maxn];
int dis[111][maxn];
void addedge(int u,int v,int w)
{
E[u].push_back(Edge2(v,w));
}
int cnt[maxn];//每个点的入队列次数
bool SPFA(int start,int n,int *dist)
{
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;i++) dist[i]=INF;
vis[start]=true;
dist[start]=0;
queue<int>que;
while(!que.empty())que.pop();
que.push(start);
memset(cnt,0,sizeof(cnt));
cnt[start]=1;
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=false;
for(int i=0;i<E[u].size();i++)
{
int v=E[u][i].v;
if(dist[v]>dist[u]+E[u][i].cost)
{
dist[v]=dist[u]+E[u][i].cost;
if(!vis[v])
{
vis[v]=true;
que.push(v);
if(++cnt[v]>n)return false;
}
}
}
}
return true;
}
int main()
{
//freopen ("in.txt", "r", stdin);
int t, kase = 0;
scanf ("%d", &t);
while (t--) {
scanf ("%d%d%d", &n, &m, &q);
printf ("Case %d:\n", ++kase);
for (int i = 1; i <= n; i++) E[i].clear ();
for (int i = 1; i <= m; i++) {
scanf ("%d%d%d", &e[i][0], &e[i][1], &w[i]);
addedge (e[i][0], e[i][1], w[i]);
addedge (e[i][1], e[i][0], w[i]);
}
build ();
int node[maxn], node_cnt = 0;//非树边的点
for (int i = 1; i <= m; i++) if (!is_edge[i]) {//枚举非树边
//cout << e[i][0] << "..." << e[i][1] << endl;
node[node_cnt++] = e[i][0], node[node_cnt++] = e[i][1];
}
sort (node, node+node_cnt);
node_cnt = unique (node, node+node_cnt)-node;
for (int i = 0; i < node_cnt; i++) {//找到每个非树边点到其他点的最短路
SPFA (node[i], n, dis[i]);
/*cout << node[i] << endl;
for (int j = 1; j <= n; j++) {
cout << "j: " << dis[i][j] << endl;
}*/
}
while (q--) {
int u, v;
scanf ("%d%d", &u, &v);
long long d1 = dis[0][u]+dis[0][v];
for (int i = 1; i < node_cnt; i++)
d1 = min (d1, (long long)dis[i][u]+dis[i][v]);
d1 = min (d1, d[u]+d[v]-(long long)2*d[LCA (u, v)]);
printf ("%lld\n", d1);
}
}
return 0;
}