題意:
有一張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;
}