D. Graph and Graph
思路:
乍一看问题很棘手,仔细思考一下题目要求,发现最终答案小于无穷(即不是-1)的情况,只可能是在两张图都在
u
,
v
u,v
u,v 这两个相邻点上反复横跳,这样每一步操作的代价都为0。
可以先查找一下哪些点可以作为最终点:如果点
u
u
u在图1和图2中都有
v
v
v这个邻接点,那么
u
u
u,
v
v
v当然都可以标记为最终点。
现在需要判断图1和图2从给定的起始点出发,能否到达同一个最终点,并且要得到一个最小代价。很容易联想到最短路算法,但是这个问题有两张图,要如何操作呢?题目限制了每一步操作时两张图都要一起动,而且
n
n
n 和
∑
m
\sum m
∑m 的大小都限制在1000以内,不妨将图1在
u
u
u点,图2在
v
v
v点的这一状态
(
u
,
v
)
(u,v)
(u,v) 视为一个点,每一次操作视为边,边权即为
∣
u
t
−
v
t
∣
|u_t-v_t|
∣ut−vt∣ ,新点(状态)的数量不超过
n
2
n^2
n2,边的数量不超过
m
2
m^2
m2,此时在这张“状态图”上可以跑一遍Dijkstra,得到从源状态到达每一个状态的最小代价。最终状态一定满足
u
=
=
v
u==v
u==v并且
u
u
u被标记为最终点 ,在所有最终状态里找到最小代价即为答案。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define int long long
#define pb push_back
#define pii pair<int, int>
#define FU(i, a, b) for (int i = (a); i <= (b); ++i)
#define FD(i, a, b) for (int i = (a); i >= (b); --i)
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int N = 1005;
int n, s1, s2, m1, m2;
vector<int> e1[N],e2[N];
int dis[N][N],vis[N][N];
void dj(int s1, int s2) {
memset(dis,INF,sizeof(dis));
memset(vis,0,sizeof(vis));
priority_queue<pair<int,pii>,vector<pair<int,pii>>,greater<pair<int,pii>>> qu;
dis[s1][s2]=0;
qu.push({0,{s1,s2}});
while(!qu.empty()){
int t1=qu.top().second.first,t2=qu.top().second.second;
qu.pop();
if(vis[t1][t2]==1)continue;
vis[t1][t2]=1;
for(int j1:e1[t1]){
for(int j2:e2[t2]){
if(dis[j1][j2]>dis[t1][t2]+abs(j1-j2)){
dis[j1][j2]=dis[t1][t2]+abs(j1-j2);
qu.push({dis[j1][j2],{j1,j2}});
}
}
}
}
}
void solve() {
cin >> n >> s1 >> s2;
FU(i, 1, n) {
e1[i].clear();
e2[i].clear();
}
// memset(bj,0,sizeof(bj));
cin >> m1;
FU(i, 1, m1) {
int x,y;
cin>>x>>y;
e1[x].pb(y);
e1[y].pb(x);
}
cin >> m2;
FU(i, 1, m2) {
int x,y;
cin>>x>>y;
e2[x].pb(y);
e2[y].pb(x);
}
bool bj[N]={},noans=1;
FU(i,1,n){
for(int e:e1[i]){
if(find(e2[i].begin(),e2[i].end(),e)!=e2[i].end()){
bj[i]=1;
noans=0;
break;
}
}
}
if(noans){
cout<<"-1\n";
return;
}
// FU(i,1,n){
// if(bj[i])cout<<i<<" ";
// }
// cout<<endl;
dj(s1,s2);
// FU(i,1,n){
// FU(j,1,n){
// cout<<i<<" "<<j<<" = "<<dis[i][j]<<"; ";
// }
// cout<<endl;
// }
int ans = INF;
FU(i,1,n){
if(bj[i])
ans = min(ans,dis[i][i]);
}
if(ans == INF){
cout<<"-1\n";
}else cout<<ans<<endl;
}
signed main() {
cin.tie(0)->ios::sync_with_stdio(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}