xt是我院19级专业第一,但他认为保研并不能展示他全部的实力,所以他在22年初试一结束就加入了23考研的队伍中,并且他为了填补我院近些年来无北大研究生的空白,毅然决然决定扛起19级的大旗,在学校百年华诞之际献上他最诚挚的礼物。
xt每天都游走在寝室,食堂和图书馆,三点一线,即便是在疫情局势蔓延的形势下,凌晨三点半刚做完核酸,他六点半还是照常起来卷。现在他太忙了,好像在提前准备复试了,想让你帮个小忙,xt会给出学校的地图(有向图),并且给出寝室,食堂和图书馆的编号(编号从0开始),希望你从该图中找出一个子图,要使得在这个子图中,寝室能够到达图书馆,食堂也能到达图书馆,同时希望在这个子图中的所有边的边权之和最小。如果你找不到任何一个子图符合要求的话(),输出“xt,我好没本领!”,因为你找不到并不代表xt找不到
子图的定义:
从原图中删去一些点或删去一些线或既删去一些点又删去一些线,剩下的部分(当然必须仍然是图)。允许两种极端情况:什么都不删;删去所有点和所有线。
输入格式:
第一行输入点的个数 n,3 <= n <= 105,边的个数 m,0 <= m <= 2∗105
第二行给出寝室的编号id1,食堂的编号id2,图书馆的编号id3,题目保证三个编号两两不同。
随后 m 行按照以下形式描述边,表示有一条有向边,起点是from,终点是to,权值是w
from to w
0 <= from, to <= n - 1,from != to,1 <= w <= 10^9
输出格式1:
如果子图存在则输出最小边权和,如果不存在输出“xt,我好没本领!”
输入样例1:
6 9
0 1 5
0 2 2
0 5 6
1 0 3
1 4 5
2 1 1
2 3 3
2 3 4
3 4 2
4 5 1
输出样例1:
9
解释:
上图为输入的图。
蓝色边为最优子图之一。
注意,直接选择0 1 5
三点构成的子图也能得到最优解,但无法在满足所有限制的前提下,得到更优解。
输入样例2:
3 2
0 1 2
0 1 1
2 1 1
输出样例2:
xt,我好没本领!
解释:
上图为输入的图。
可以看到,不存在从节点 1 到节点 2 的路径,所以不存在任何子图满足所有限制。
思路:
1.跑以寝室,食堂为起点的最短路,存入d_1, d_2 。
2.跑以图书馆为起点的反向最短路,存入d_3。
3.便历从0->n所有点,以d_1[i] + d_2[i] + d_3[i] 为所有点到这个点的路径长度,
一直取其最小(ans=min(d_1[i] + d_2[i] + d_3[i],ans)。
如果未改变,就按题目要求输出,改变了就输出ans;
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pli pair<ll,int>
ll n , m , k , idx , cnt;
const ll inf = 0x3f3f3f3f3f3f/3;
const int l = 200005;
const int r = 100005;
int ne_12[l] , e_12[l] , h_12[l] ;
int ne_3 [l] , e_3 [l] , h_3 [l] ;
ll d_1[r] , d_2[r] , d_3[r] , dist_12[r] , w_12[l] , w_3 [l];
bool st[r];
void add(int a,int b,int c){
ne_12[idx] = h_12[a];
e_12[idx] = b;
w_12[idx] = c;
h_12[a] = idx ++;
/*QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ QWQ*/
ne_3[cnt] = h_3[b];
e_3[cnt] = a;
w_3[cnt] = c;
h_3[b] = cnt ++;
}
void bfs_12(int x){
memset(st , 0 ,sizeof st);
for(int i = 0 ; i < n ; i ++)dist_12[i] = inf;
priority_queue<pli,vector<pli>,greater<pli> >q;
q.push({0,x}); dist_12[x] = 0;
while(!q.empty()){
int t = q.top().second;
q.pop();
if(st[t])continue;
st[t] = 1;
for(int i = h_12[t] ; i != -1 ; i = ne_12[i]){
int to = e_12[i];
if(dist_12[to] <= dist_12[t] + w_12[i])continue;
dist_12[to] = dist_12[t] + w_12[i];
q.push({dist_12[to],to});
}
}
}
void bfs_3(int x){
memset(st , 0 , sizeof st);
for(int i = 0 ; i < n ; i ++)d_3[i] = inf;
priority_queue<pli,vector<pli>,greater<pli> >q;
q.push({0,x});d_3[x] = 0;
while(!q.empty()){
int t = q.top().second;
q.pop();
if(st[t])continue;
st[t] = 1;
for(int i = h_3[t] ; i != -1 ; i = ne_3[i]){
int to = e_3[i];
if(d_3[to] <= d_3[t] + w_3[i])continue;
d_3[to] = d_3[t] + w_3[i];
q.push({d_3[to],to});
}
}
}
int main(){
int qs , st , tsg;
cin >> n >> m;
cin >> qs >> st >> tsg;
idx = cnt = 0;
memset(h_3 , -1 , sizeof h_3);
memset(h_12 , -1 , sizeof h_12);
while(m --){
int a , b , c;
cin >> a >> b >> c;
add(a,b,c);
}
bfs_12(st);for(int i = 0 ; i < n ; i ++)d_1[i] = dist_12[i];
bfs_12(qs);for(int i = 0 ; i < n ; i ++)d_2[i] = dist_12[i];
bfs_3(tsg);
ll ans = inf;
for(int i = 0 ; i < n ; i ++){
if(d_1[i] >= inf || d_2[i] >= inf || d_3[i] >= inf
|| d_1[i] < 0 || d_2[i] < 0 || d_3[i] < 0)continue;
ans = min(ans,d_1[i]+d_2[i]+d_3[i]);
}
if(ans >= inf)cout << "xt,我好没本领!\n";
else cout << ans << endl;
}