1. 程式人生 > >POJ 3463 Sightseeing (最短路&次短路條數問題)

POJ 3463 Sightseeing (最短路&次短路條數問題)

題意:給一個有向圖,求從s到f 的最短路+最短路-1的條數。   有重邊。

分析: 程式碼是根據挑戰的次短路改編的。      具體請看程式碼。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<iomanip>
#include<sstream>
#include<limits>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const ll INF = 1e18;
const int maxn = 2e5+10;
const ll MOD = 1000000007;
const double EPS = 1e-10;
const double Pi = acos(-1.0);

struct edge{int to,cost;};
//typedef pair<int,int>P; //1 dist 2 u
struct P{
    int first,second,z;   //z 標誌是最短路還是次短路
    P(int a=0,int b=0,int c=0):first(a),second(b),z(c){}
    bool operator < (const P &rhs)const{return first>rhs.first;}
};
int V;
vector<edge>G[maxn];
int d[maxn],d2[maxn],cnt1[maxn],cnt2[maxn],vis[maxn][2];  //d cnt1 最短路長度及數量 d2 cnt2 次短路長度及數量  vis代表有沒訪問過
void dij(int s)
{
    priority_queue<P >que;
    fill(d,d+V+1,inf);
    fill(d2,d2+V+1,inf);
    d[s] = 0;
    cnt1[s] = 1;
    que.push(P(0,s,0));
    while(!que.empty())
    {
        P p = que.top(); que.pop();
        int v = p.second, z = p.z;
        if (d2[v] < p.first || vis[v][z]) continue;
        vis[v][z] = 1;       //一定要記錄是否訪問過,不然會出錯,因為是單調佇列。
        for(int i = 0; i < G[v].size();i++)
        {
            edge e = G[v][i];
            int temp = p.first + e.cost;

            if (d[e.to] > temp)  // 比最短路短
            {
                d2[e.to] = d[e.to];
                d[e.to] = temp;
                cnt2[e.to] = cnt1[e.to];
                cnt1[e.to] = z==0? cnt1[v]:cnt2[v];   //要弄清楚等於哪個。

                que.push(P(d[e.to] ,e.to,0));
                que.push(P(d2[e.to] ,e.to,1));
            }else
              if (d[e.to] == temp) cnt1[e.to] += z==0? cnt1[v]:cnt2[v];   // 等於最短路
              else
                if (temp < d2[e.to])   // 比次短路短
                {
                    d2[e.to] = temp;
                    cnt2[e.to] = z==0? cnt1[v]:cnt2[v];
                    que.push(P(d2[e.to] ,e.to,1));
                }else if (temp == d2[e.to]) cnt2[e.to] += z==0? cnt1[v]:cnt2[v];  // 等於次短路
        }
    }
}
int main(){
#ifdef LOCAL
	freopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);
	//freopen("output.txt","w",stdout);
#endif
//ios_base::sync_with_stdio(0);
     int T,n,m;
     scanf("%d",&T);
     while(T--)
     {
         scanf("%d%d",&n,&m);
         for(int  i = 0; i <= n; i++) G[i].clear();
         V = n;
         for(int i = 0; i < m; i++)
         {
             int a,b,l;
             scanf("%d%d%d",&a,&b,&l);
             G[a].push_back(edge{b,l});
         }
         int s,f;
         scanf("%d%d",&s,&f);
         memset(cnt1,0,sizeof cnt1);
         memset(cnt2,0,sizeof cnt2);
         memset(vis,0,sizeof vis);
         dij(s);

         if (d[f] == d2[f]-1) cnt1[f] += cnt2[f];
         printf("%d\n",cnt1[f]);
     }
    return 0;
}