[POI 2013]Tales of seafaring(BFS)

21 篇文章 0 订阅

题目链接

http://main.edu.pl/en/archive/oi/20/mor

题目大意

给定一张无向图,图中每条边边权均为1,多次询问是否存在一个长度为 d ,从点x到点 y 的路径。

思路

注意到虽然询问次数非常多,但是点数和边数非常少。
考虑对询问进行排序,每次统一回答一些起点相同的询问。
注意到一条长度为d的路径,可以通过反复走某条边,变成长度为 d+2,d+4... 的路径。
因此,以点 S 为起点BFS时,可以记录下从S到某个点长度为偶数和奇数的最短路长度。假如当前的询问是从 S x的长度为 d 的路径,且d为偶数,那么若从 S 到点x长度为偶数的最短路是小于等于 d <script type="math/tex" id="MathJax-Element-313">d</script>的,则表明有解,否则显然是无解的。

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXE 5100
#define MAXV 5100

using namespace std;

struct edge
{
    int u,v,next;
}edges[MAXE*2];

int head[MAXV],nCount=0;

void AddEdge(int U,int V)
{
    edges[++nCount].u=U;
    edges[nCount].v=V;
    edges[nCount].next=head[U];
    head[U]=nCount;
}

struct Node
{
    int x,flag;
    Node(){}
    Node(int _x,int _f):x(_x),flag(_f){}
}q[MAXE*2];

int mindist[MAXV][2]; //mindist[i][0]=S到点i的长度为偶数的路径个数

void BFS(int S)
{
    memset(mindist,-1,sizeof(mindist));
    mindist[S][0]=0;
    int h=0,t=1;
    q[h]=Node(S,0);
    while(h<t)
    {
        Node now=q[h++];
        int u=now.x;
        for(int p=head[u];p!=-1;p=edges[p].next)
        {
            int v=edges[p].v;
            if(mindist[v][now.flag^1]==-1)
            {
                mindist[v][now.flag^1]=mindist[u][now.flag]+1;
                q[t++]=Node(v,now.flag^1);
            }
        }
    }
}

struct Query
{
    int S,T,dis,id;
    bool ans;
}query[1100000];

bool cmp(Query a,Query b)
{
    return a.S<b.S;
}

bool cmp2(Query a,Query b)
{
    return a.id<b.id;
}

int n,m,K;
bool connected[MAXV];

int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        AddEdge(u,v);
        AddEdge(v,u);
        connected[u]=connected[v]=true;
    }
    for(int i=1;i<=K;i++)
    {
        query[i].id=i;
        scanf("%d%d%d",&query[i].S,&query[i].T,&query[i].dis);
    }
    sort(query+1,query+K+1,cmp);
    for(int i=1;i<=K;i++)
    {
        int tmp=i;
        BFS(query[i].S);
        while(i<=K&&query[i].S==query[tmp].S)
        {
            if(query[i].S==query[i].T&&!connected[query[i].S]) query[i].ans=false; //!!!!注意特判
            else
            {
                if(query[i].dis&1)
                {
                    if(query[i].dis>=mindist[query[i].T][1]&&mindist[query[i].T][1]!=-1)
                        query[i].ans=true;
                    else query[i].ans=false;
                }
                else
                {
                    if(query[i].dis>=mindist[query[i].T][0]&&mindist[query[i].T][0]!=-1)
                        query[i].ans=true;
                    else query[i].ans=false;
                }
            }
            i++;
        }
        i--;
    }
    sort(query+1,query+K+1,cmp2);
    for(int i=1;i<=K;i++)
    {
        if(query[i].ans)
            printf("TAK\n");
        else
            printf("NIE\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值