1. 程式人生 > >11.3清北集訓最短路奇偶拆點

11.3清北集訓最短路奇偶拆點

在這裡插入圖片描述
在這裡插入圖片描述

solution

  1. 顯然假如詢問u->v,w為奇數,如果u->v的奇數最短路<=w,那麼這組詢問一定是yes,偶數與之相同
  2. 所以我們只要求出任意u->v的奇數偶數最短路即可
  3. 如何??
  4. 我們考慮u->v的一條邊我們把它拆成u->v+n和u+n->v的兩條邊
  5. u到v的最短路就拆成了u->v(偶數)和u->v+n(奇數)兩種.
    在這裡插入圖片描述

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
inline int read(){
	char ch=' ';int f=1;int x=0;
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
const int N=2200;
const int M=10100;
struct node
{
	int v,nxt;
}edge[M<<1];
int head[N],cnt;
void add(int u,int v)
{
	cnt++;
	edge[cnt].v=v;
	edge[cnt].nxt=head[u];
	head[u]=cnt;
}
int dis[N][N];
int q[N],h,t;
bool a[N];
int n;
void bfs(int s)
{
	for(int i=1;i<=n*2;i++) dis[s][i]=-1;
	if(a[s]) return ;
	h=1;t=0;q[++t]=s;dis[s][s]=0;
	while(h<=t)
	{
		int u=q[h++];
		for(int i=head[u];i;i=edge[i].nxt)
		{
			int v=edge[i].v;
			if(dis[s][v]==-1)
			{
				dis[s][v]=dis[s][u]+1;
				q[++t]=v;
			}
		}
	}
}
int main()
{
	freopen("chase.in","r",stdin);
	freopen("chase.out","w",stdout);
	int m;
	n=read();m=read();
	int i,j;int x,y,k;
	for(i=1;i<=n;i++) a[i]=true;
	for(i=1;i<=m;i++)
	{
		x=read();y=read();
		add(x,y+n);add(x+n,y);
		add(y+n,x);add(y,x+n);
		a[x]=a[y]=false;
	}
	for(i=1;i<=n;i++)
	{
		bfs(i);
	}
	int T=read();
	while(T--)
	{
		int x=read(),y=read(),k=read();
		if(a[x])
		{
			puts("no");
		}
		else if((k%2)&&(dis[x][y+n]<=k)&&(dis[x][y+n]>=0)||
		!(k%2)&&(dis[x][y]<=k)&&(dis[x][y]>=0))
		{
			puts("yes");
		}
		else
		{
			puts("no");
		}
	}
	return 0;
}