[POI2013]MOR-Tales of seafaring

  • 题意

给n个点m条边无向图,每次询问两个点之间是否有长度为d的路径(不一定是简单路径)(LG题意吼啊只要一句话)

  • solution

不一定是简单路径! 所以实际上两个点之间长度为d的路径其实是一条简单路径+一条边上的反复横跳

syk大佬:所以只要求出任意两点间的奇偶最短路就好了

为什么呢?显然 我们找一条奇偶性与d相同的最短简单路径,如果这条路径长度<d就TAK

所以现在我们要求奇偶最短路,首先普通最短路很简单,因为边权为1所以每个点bfs一遍就好了,对于奇偶最短路,我是这样的
对于每次bfs(s)记pos1[x]为从s到x的奇数最短路,pos2[x]为从s到x的偶数最短路,那么

        pos2[to]=min(pos2[to],pos1[x]+1);
        pos1[to]=min(pos1[to],pos2[x]+1);

这样交替更新()就好了
注意特判这样的数据

1 0 2
1 1 0
1 1 2
\\TAK NIE
  • code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#define N 5050
using namespace std;
vector<int> G[N];
int n,m,k;
int dis1[N][N],dis2[N][N];
int pos1[N],pos2[N],dd[N];
queue<int>q;
bool vis[N];
void bfs(int s){
memset(pos1,0X3f,sizeof pos1);
memset(pos2,0X3f,sizeof pos2);
memset(vis,0,sizeof vis);
while(!q.empty())q.pop();
pos2[s]=0;vis[s]=1;
q.push(s);
while(!q.empty()){
    int x=q.front();
    q.pop();vis[x]=0;
    for(int i=0;i<G[x].size();i++){
        int to=G[x][i];
        if(!vis[to]&&((pos2[to]>pos1[x]+1)||(pos1[to]>pos2[x]+1))){vis[to]=1;q.push(to);}
        pos2[to]=min(pos2[to],pos1[x]+1);
        pos1[to]=min(pos1[to],pos2[x]+1);
    }
}
for(int i=1;i<=n;i++)dis1[s][i]=pos1[i],dis2[s][i]=pos2[i];
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++){
    int a,b;
    scanf("%d%d",&a,&b);
    G[a].push_back(b),G[b].push_back(a);
    dd[a]++,dd[b]++;
}
for(int i=1;i<=n;i++)bfs(i); 
for(int i=1;i<=k;i++){
    int x,y,d;
    scanf("%d%d%d",&x,&y,&d);
    if(x==y&&d&&(!dd[x])){puts("NIE");continue;}
    if(d&1){
        if(dis1[x][y]<=d)puts("TAK");
        else puts("NIE");
    }
    else {
        if(dis2[x][y]<=d)puts("TAK");
        else puts("NIE");
    }
}
}

其实这里我开两个int[5000][5000]空间会爆,应该用short或者用离线算法,但是不知道为什么没爆 所以就不改了

posted @ 2019-09-25 20:16  stepsys  阅读(...)  评论(...编辑  收藏