题意:在一个无向图中要寻找编号第一个节点到编号第二个节点的路径个数,路径满足所有(a->b)满足存在一条从b出发去东区的路,比所有从a出发去终点的路都短。最后是输出路径数。最多1000个点。
思路:原题中不含重边在,在月赛中的测试数据里我加入了重边所以只能用邻接表作为存储结构。仔细分析一下条件我们可以发现只要满足b的最短路比a短a->b的路径就是可以走的。所以我们需要先对2号结点执行Dijkstra算法算出所有结点到终点的距离。然后就是记忆化搜索,dp[i]表示存在多少条从i到终点的路径。接着输出dp[0]就行了。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <queue> 8 #include <stack> 9 #include <vector> 10 #define PB(a) push_back(a) 11 #define MP(a, b) make_pair(a, b) 12 13 using namespace std; 14 15 typedef long long ll; 16 typedef pair<unsigned int, unsigned int> pii; 17 typedef pair<int, ll> pil; 18 19 const int INF = 0x3f3f3f3f; 20 const double eps = 1e-6; 21 const int LEN = 1010; 22 23 vector<pii> Map[LEN]; 24 int n, m, dis[LEN], dp[LEN]; 25 26 void Dijkstra(int s) 27 { 28 priority_queue<pii, vector<pii>, greater<pii> > q; 29 int vis[LEN] = {0}; 30 for(int i=1; i<=n; i++)dis[i] = INF; 31 dis[s] = 0; 32 q.push(MP(dis[s], s)); 33 while(!q.empty()){ 34 pii nvex = q.top(); q.pop(); 35 int nv = nvex.second; 36 if(vis[nv])continue; 37 vis[nv] = 1; 38 for(int i=0; i<Map[nv].size(); i++){ 39 int x = Map[nv][i].first; 40 ll y = Map[nv][i].second; 41 if(dis[x]>dis[nv]+y){ 42 dis[x] = dis[nv]+y; 43 q.push(MP(dis[x], x)); 44 } 45 } 46 } 47 } 48 49 int dfs(int vex) 50 { 51 if(dp[vex]!=-1) return dp[vex]; 52 int ret = 0; 53 for(int i=0; i<Map[vex].size(); i++){ 54 int x = Map[vex][i].first; 55 if(dis[x]>dis[vex])ret+=dfs(x); 56 } 57 return dp[vex] = ret; 58 } 59 60 int main() 61 { 62 //freopen("in.txt", "r", stdin); 63 64 while(scanf("%d", &n)!=EOF && n){ 65 scanf("%d", &m); 66 for(int i=1; i<=n; i++)Map[i].clear(); 67 int a, b, c; 68 for(int i=0; i<m; i++){ 69 scanf("%d%d%d", &a, &b, &c); 70 Map[a].PB(MP(b, c)); 71 Map[b].PB(MP(a, c)); 72 } 73 Dijkstra(2); 74 memset(dp, -1, sizeof dp); 75 dp[1] = 1; 76 int ans; 77 ans = dfs(2); 78 printf("%d ", ans); 79 } 80 return 0; 81 }