题意:
有一张n个点的图,任意两个点之间都有一条虚边或实边。现在有两个小朋友想从点1走到点n,一个小朋友只能走虚边,一个小朋友只能走实边。现在问这两个小朋友都走到终点最少需要多少时间。如果没有合法方案输出-1。
Input
第一行包含两个整数 n 和 m (2 ≤ n ≤ 400, 0 ≤ m ≤ n(n - 1) / 2) — 表示点数和实边的数量。
之后 m 行包含两个整数 u 和 v,表示一条连接 u 和 v 的实边。 (1 ≤ u, v ≤ n, u ≠ v)
保证任意两点之间最多有一条实边。
Output
输出一个整数 — 最少需要的时间。
思路:
即对给出的图和其补图求起点到终点的最短路,两者取最大值。特殊的是其中一个图一定会包含1-n这条边,因此这个图的最短路就是1,只用跑另一个就可以。
ac代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#include<unordered_map>
#define mod (1000000007)
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
const int inf=0x3f3f3f3f;
struct node{
int v,nxt;
}side[maxn];
int head[1000],cnt=0,dis[1000],vis[1000];
void add(int x,int y){
side[cnt].v=y;
side[cnt].nxt=head[x];
head[x]=cnt++;
}
map<pair<int,int>,int> mp;
int bfs(int st,int ed){
for(int i=0;i<=500;i++) dis[i]=inf,vis[i]=0;
queue<int> q;
dis[st]=0;
q.push(st);
while(!q.empty()){
int nn=q.front();
q.pop();
if(vis[nn]) continue;
if(nn==ed) break;
vis[nn]=1;
for(int i=head[nn];i!=-1;i=side[i].nxt){
int ty=side[i].v;
if(dis[ty]>dis[nn]+1){
dis[ty]=dis[nn]+1;
q.push(ty);
}
}
}
return dis[ed]==inf?-1:dis[ed];
}
int main(){
int n,m,u,v,ff=0;
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++) head[i]=-1;
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);
if(u>v) swap(u,v);
if(u==1&&v==n) ff=1;
mp[make_pair(u,v)]=1;
add(u,v);
add(v,u);
}
if(ff){
cnt=0;
for(int i=0;i<=n;i++) head[i]=-1;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(!mp[make_pair(i,j)]){
add(i,j);add(j,i);
}
}
printf("%d\n",bfs(1,n));
return 0;
}