UESTC Training for Graph Theory——K、Blinking Stalkers

Blinking Stalkers

Time Limit: 2000 ms Memory Limit: 65536 kB Solved: 152 Tried: 1656

Description

In Starcraft II, Stalker is an unusual kind of unit for its amazing ability called "blink". Blink means you can move from one position to another one immediately as long as the distance between the two position is less than D. Now, there is N stalkers on some islands, and everyone have a target island to go. And of course, targets of them can be variable. Because any stalker can't move on water, they can only blink between islands. For some strange reason, only some particular pairs of island are allowed to blink. Your task is to determine whether they can move to their target island.

Input

In the first line of input there is an integer T, which indicates there are T test cases in the input.
For each test case, the first line contains two integer n(2<=n<=1000), m(1<=m<=100000), meaning there are n islands and m pairs island where stalkers can blink. Then m lines followed, each line contain three integer u, v, w, (1<=u, v<=n), (0< w <= 1000000), which means a stalker can blink from u to v or v to u, and the distance is w. Then a single line contains a integer Q(1<=Q<=3000), which indicates there are Q stalkers. Then Q lines followed, each line contain three integer a, b, c, (1<=a, b<=n), (0 < c <= 1000000), meaning this stalker start at island a and target island is b, the distance it can blink is c. You can assume that the graph described in every test case is connected.

Output

For each test case, output Q+1 lines. First, output "Case #C: ", where C is the number of test case, from 1 to T. Then output Q lines, if the ith stalker can move to its target island using its ability for finite times, output “YES” in a single line, otherwise output “NO”.

Sample Input

1
3 3
1 2 2
1 3 3
2 3 2
2
1 3 1
1 3 2

Sample Output

Case #1:
NO
YES

Source

elfness

 

/*算法思想:
  给一个带权图,还有一些询问,问能否从点 i 到点 j ,使得经过的路径里面最长的路径长度不超过 k
  这个要求相当于是说要求经过的边的长度尽可能短,那么我们不难联想到先给原图求一个最小生成树,
  因为这样我们每次访问两个点之间的时候,经过的路径长度肯定是尽量短的。
  然后我们就可以对每个询问BFS一次,看能否访问到目标节点,每次遍历的最大时间就是o(n),所以不会超时
*/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define N 2000
using namespace std;
struct data
{
    int st,en,val,next;
} edge[400005],e[2*N];
int n,m,head[N];
int fa[N];
bool vs[N];
void make_set()
{
    for(int i=0;i<=n;i++)
        fa[i]=i;
}
int find_set(int x)
{
    if(x!=fa[x]) fa[x]=find_set(fa[x]);
    return fa[x];
}
void merge_set(int x,int y)
{
    fa[x]=y;
}
bool cmp(data a,data b)
{
    if(a.st==b.st) return a.val<b.val;
    else return a.st<b.st;
}
bool cmpp(data a,data b)
{
    return a.val<b.val;
}
void kruskal()  //求最小生成树
{
    memset(fa,0,sizeof(fa));
    make_set();
    int tot=0;
    for(int i=1;i<=2*m;i++)
    {
        int f1=find_set(edge[i].st);
        int f2=find_set(edge[i].en);
        if(f1!=f2)
        {
            merge_set(f1,f2);
            e[++tot]=edge[i];
        }
        if(tot==n-1) return;  //找够边了,退出
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int  ca=1;ca<=t;ca++)
    {
        memset(edge,-1,sizeof(edge));
        memset(e,-1,sizeof(e));
        memset(head,-1,sizeof(head));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            edge[i+m].en=edge[i].st=a;
            edge[i+m].st=edge[i].en=b;
            edge[i+m].val=edge[i].val=c;
        }
        sort(edge+1,edge+2*m+1,cmpp);
        kruskal();
        for(int i=1;i<n;i++)
        {
            e[i+n-1].st=e[i].en;
            e[i+n-1].en=e[i].st;
            e[i+n-1].val=e[i].val;
        }
        sort(e+1,e+2*n-1,cmp);
        head[e[1].st]=1;
        int i=1;
        while(i<2*n-1)
        {
            while(e[i].st==e[i+1].st && i+1<2*n-1)
            {
                e[i].next=i+1;
                i++;
            }
            e[i].next=-1;
            i++;
            if(i<2*n-1) head[e[i].st]=i;
        }
        int Q;
        printf("Case #%d:\n",ca);
        scanf("%d",&Q);
        for(int i=0;i<Q;i++)
        {
            queue<int>q;
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            bool fg=false;
            memset(vs,0,sizeof(vs));
            q.push(a); vs[a]=true;  //对每个询问BFS遍历一次
            while(!q.empty())
            {
                int now=q.front();
                q.pop();
                if(now==b)
                {
                    fg=true;
                    break;
                }
                int pos=head[now];
                if(pos==-1) continue;
                while(e[pos].val<=c && pos!=-1)
                {
                    if(!vs[e[pos].en])
                    {
                        q.push(e[pos].en);
                        vs[e[pos].en]=true;
                    }
                    pos=e[pos].next;
                }
            }
            fg?printf("YES\n"):printf("NO\n");
        }
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值