题目链接:https://vjudge.net/problem/UVA-10917
题意:Jimmy打算每天沿着一条不同的路走,而且,他只能沿着满足如下条件的道路(A,B):存在一条从B出发回家的路径,比所有从A出发回家的路径都短,你的任务是计算有多少条不同的路径
注意,这里出发点为1,目的点为2。
思路,
1 以点2为目的地,使用Dijkstra计算各个点到终点的路径,这里有现成的Dijkstra算法框架,已经写成了struct形式,可以直接调用,但是节点编号都是从0开始,所以输入的是Dijkstra(1)。求的各个点到目的的路径长度。
2。判断给的所有边中符合条件的边,即起点>终点,剔除不需要的边
3.使用DP处理,比如最后一个点2,达到他的路径等于所有的入度为2的路径之和,注意使用“记忆”,否则会超时间。
4.Dijkstra的框架已经现成,以后可以调用,但是该算法无法满足权重为负数的情况。这里使用了优先级队列,值得学习品味。
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <iostream>
using namespace std;
const int maxn=1005;
const int INF=0x3f3f3f3f;
struct Edge {
int from,to,dist;
};
struct HeapNode {
int d,u;
bool operator < (const HeapNode& rhs) const {
return d>rhs.d;
}
};
struct Dijkstra {
int n,m;
int d[maxn],p[maxn];
bool done[maxn];
vector<Edge> edges;
vector<int> G[maxn];
void init(int n) {
this->n=n;
for(int i=0; i<n; i++)G[i].clear();
edges.clear();
}
void AddEdge(int from,int to,int dist) {
edges.push_back((Edge) {
from,to,dist
});
m=edges.size();
G[from].push_back(m-1);
}
void dijkstra(int s) {
priority_queue<HeapNode> Q;
int u;
HeapNode x;
for(int i=0; i<n; i++)d[i]=INF;
d[s]=0;
memset(done,0,sizeof(done));
Q.push((HeapNode) {
0,s
});
while(!Q.empty()) {
x=Q.top();
Q.pop();
u=x.u;
if(done[u])continue;
done[u]=true;
for(int i=0; i<G[u].size(); i++) {
Edge& e=edges[G[u][i]];
if(d[e.to] > d[e.from]+e.dist) {
d[e.to]=d[e.from]+e.dist;
p[e.to]=G[u][i];
Q.push((HeapNode) {
d[e.to],e.to
});
}
}
}
}
void print(int ibegin,int iend) {
cout<<d[iend]<<":";
stack<int> path;
path.push(iend);
while(iend!=ibegin) {
Edge t=edges[p[iend]];
path.push(t.from);
iend=t.from;
};
int ecount=path.size();
for(int i=0; i<ecount; i++) {
if(i>0) cout<<"---";
cout<<path.top();
path.pop();
}
}
};
int n;
Dijkstra solver;
vector<int> Map[maxn];
int dp[maxn];
int dfs(int s) {
if(dp[s]>-1) return dp[s];
int sum=0;
for(int i=0; i<Map[s].size(); i++)
sum+=dfs(Map[s][i]);
dp[s]=sum;
return sum;
}
int main() {
int m,a,b,c;
while(~scanf("%d%d",&n,&m)&&n) {
solver.init(n);
while(m--) {
scanf("%d%d%d",&a,&b,&c);
a--;
b--;
solver.AddEdge(a,b,c);
solver.AddEdge(b,a,c);
}
solver.dijkstra(1);//注意,这里是开始点,所以的点从0开始
//for(int i=0;i<n;i++) cout<<solver.d[i]<<endl;
//solver.print(0,1); 如果需要,可以打印路径
for(int i=0; i<n; i++)Map[i].clear();
for(int i=0; i<solver.edges.size(); i++) { //按照入度
Edge te=solver.edges[i];
if(solver.d[te.from]>solver.d[te.to]) {
Map[te.to].push_back(te.from);
}
}
//for(int i=0;i<n;i++) cout<<Map[i].size()<<endl;
memset(dp,-1,sizeof(dp));
dp[0]=1;
cout<<dfs(1)<<endl;
}
return 0;
}