路径 ssl 2651 spfa+暴力

32 篇文章 0 订阅
17 篇文章 0 订阅

题目大意

给出一个n个点m条边的无向图,每条边的长度均为1,要求回答k个询问,每次询问给出(s,t,d),问是否存在一条从s到t的路径,长度为d,若有满足的路径,则输出TAK,否则输出NIE。每个点每条边允许经过多次。

分析

如果s到t有长度为d的路径 那么就一定有长度为d+2的路径
因此只要spfa求出s开始到每个点的奇数长度的最短路和偶数长度的最短路(分层图)。
然后和D比较大小。
特判自己连自己的情况。

code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
#include<stack>
#include<queue> 

using namespace std;

struct arr{
    int x,y,w,next;
}edge[50000];
int ls[10000]; 
int dis[5002][5002][2];
int v[5002][2];
int n,m,k,s,t;
int edge_m;


void add(int x,int y,int w)
{
    edge_m++;
    edge[edge_m]=(arr){x,y,w,ls[x]};ls[x]=edge_m;
    edge_m++;
    edge[edge_m]=(arr){y,x,w,ls[y]};ls[y]=edge_m;
}

void spfa()
{
    for (int i=1;i<=n;i++)  dis[s][i][1]=2000000000,dis[s][i][0]=2000000000;
    memset(v,0,sizeof(v));
    queue<int> q;
    queue<int> qq;
    dis[s][s][0]=0;
    qq.push(0);
    q.push(s); v[s][0]=1;
    do{
        int x=q.front();
        int xx=qq.front();
        for (int i=ls[x];i;i=edge[i].next)
            if (dis[s][edge[i].y][xx^1]>dis[s][x][xx]+edge[i].w)
            {
                dis[s][edge[i].y][xx^1]=dis[s][x][xx]+edge[i].w;
                if (!v[edge[i].y][xx^1])
                {
                    v[edge[i].y][xx^1]=1;
                    q.push(edge[i].y);
                    qq.push(xx^1);
                }
            }
        v[x][xx]=0;
        q.pop();
        qq.pop();
    }while (!q.empty());
}

int vv[10000];
int vvv[10000];

int main()
{
    freopen("way.in", "r", stdin);
    freopen("way.out", "w", stdout);
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        vvv[x]=1;
        vvv[y]=1;
        if (x==y)
            vv[x]=1;
        add(x,y,1);
    }
    for (int i=1;i<=n;i++)
    {
        s=i;
        spfa();
    }
    for (int i=1;i<=k;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        s=x; t=y;
        if (x==y)
        {
            if (z%2)
                if (dis[s][t][1]<=z)
                    printf("TAK\n");
                else
                    printf("NIE\n");
            else
                if (vvv[x])
                    printf("TAK\n");
                else
                    printf("NIE\n");
            continue;
        }
        if (z%2)
            if (dis[s][t][1]<=z)
                printf("TAK\n");
            else
                printf("NIE\n");
        else
            if (dis[s][t][0]<=z)
                printf("TAK\n");
            else
                printf("NIE\n");
    }
    fclose(stdin);
    fclose(stdout);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值