题目链接:http://codeforces.com/gym/101149/problem/L
题目大意:有n个点(其实是n+1个点,因为编号是0~n),m条有向边。起点是0,到a和b两个节点,所经过的最少的节点的数目是多少?(a和b也算,0不算)
思路:
真的是想了半天了,不知道怎么做,虽然知道是最短路,还是偏离了方向。最后万不得已的翻了题解。
题解看的是这个人的:链接
思路大体就是:
因为如果要到两个点,路径上的点肯定是有相交点的(因为0是必然要走的)。然后如果两者路径相交,肯定选择共同相交的走。所以说,两条路径的刚开始是必然相交的,到后来才会分开。
所以我们就只需要求出distance,然后o->c + a->c + b->c的距离就好了
//看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespace std; #pragma comment(linker,"/STACK:102400000,102400000") #define LL long long #define ALL(a) a.begin(), a.end() #define pb push_back #define mk make_pair #define fi first #define se second #define haha printf("haha ") const int maxn = 2e5 + 5; const int inf = 0x3f3f3f3f; int n, m, a, b; vector<int> G[maxn]; pair<int, int> edges[maxn]; struct Point{ int u, dis; bool operator < (const Point &rhs) const{ return dis > rhs.dis; } }; int d1[maxn], d2[maxn], d3[maxn]; void dijstra(int s, int d[]){ for (int i = 0; i <= n; i++) d[i] = 1000000000; d[s] = 0; priority_queue<Point> que; que.push(Point{s, d[s]}); while (!que.empty()){ int u = que.top().u; que.pop(); for (int i = 0; i < G[u].size(); i++){ int v = G[u][i]; if (d[v] > d[u] + 1){ d[v] = d[u] + 1; que.push(Point{v, d[v]}); } } } } int main(){ scanf("%d%d%d%d", &n, &m, &a, &b); for (int i = 1; i <= m; i++){ int u, v; scanf("%d%d", &u, &v); edges[i] = mk(u, v); G[u].pb(v); } dijstra(0, d1); for (int i = 0; i <= n; i++){ G[i].clear(); } for (int i = 1; i <= m; i++){ int u = edges[i].se, v = edges[i].fi; G[u].pb(v); } dijstra(a, d2); dijstra(b, d3); int ans = 1000000000; for (int i = 0; i <= n; i++){ ans = min(ans, d1[i] + d2[i] + d3[i]); } cout << ans << endl; return 0; }