poj3463 Sightseeing

来源:互联网 发布:系统之间的数据交换 编辑:程序博客网 时间:2024/05/16 17:40
/* *poj3463 AC *求最短路径以及次短路径的总数。 *Dijkstra+一点变化。 *与最短路径的Dijkstra的相比,记录的东西要增加。 *算法: *首先,要记录到某结点的最短路径以及最短路径dis[i][2], *记录到某结点的最短路径以及次短路径是否算出的vis[i][2], *还要记录到大某结点的最短路径以及次短路径的路径数num[i][[2], * *tips: *由于最终结果可能到达10^9量级,所以把每一条最短路径和次短路径都找出来再求和, *是不可行的。这也是最开始使用Dijkstra+A*超时的原因。 * *然后使用Dijkstra算法,过程中同理找出最短路径以及次短路径中最短的 dis[i][0..1], *  dis[i][0..1]即代表到i的最短路径或次短路径已经找到了,置vis[i][0..1]为true, *  然后同理用dis[i][0..1]更新相连边的dis[][],此时要注意递推的过程。 *  另l = dis[i][0或1]+edge[j].l *  情况1:l小于dis[edge[j].v][0]。 *  情况2:l等于dis[edge[j].v][0]。 *  情况3:l大于dis[edge[j].v][0]但小于dis[edge[j].v][1]。 *  情况4:l等于dis[edge[j].v][1]。 *  利用STL的优先队列,要注意出队列的结点一定要判断vis[i][0..1]是否为真,即dis[i][0..1]是否已经出过一次队了, *  防止同一结点的同一路径重复出队。 *  若是自己写的优先队列,则因为所有的结点在一开始就已经入队,之后只是更新优先队列中的值,则不会出现重复出队。 *  (此处WA我的想吐血)。而由于只有1000个结点,即使不用优先队列也可以满足。 * * */#include<stdio.h>#include<memory.h>#include<queue>#include<vector>#define INF 1000000005using namespace std;int t,n,m,s,f;struct EDGE{int v,l,next;}edge[10005];struct NODE{int v,num;long dis;};int tot,head[1005];long dis[1005][2],num[1005][2];struct cmp{bool operator()(const NODE &t1,const NODE &t2){return t1.dis>t2.dis;}};inline void add(int j,int k,int p,int &tot,EDGE e[],int h[]){e[++tot].v = k,e[tot].l = p,e[tot].next = h[j],h[j] = tot;}inline void Dijkstra(){int i;NODE node,tmp;bool vis[1005][2];priority_queue<NODE,vector<NODE>,cmp> queue;for(i=1;i<=n;i++){dis[i][0] = dis[i][1] = INF;vis[i][0] = vis[i][1] = false;num[i][0] = num[i][1] = 0;}node.v = s,node.dis = 0,dis[s][0] = 0,num[s][0] = 1;node.num = 0;queue.push(node);while(!queue.empty()){node = queue.top();queue.pop();long u,v;u = node.v,v = node.num;if(vis[u][v] || node.dis>dis[u][1]) continue;//一定要判断是否重复出队了。vis[u][v]= true;for(i=head[node.v];i;i=edge[i].next){//if(!vis[edge[i].v][0] && dis[edge[i].v][0]>node.dis+edge[i].l)if(dis[edge[i].v][0]>node.dis+edge[i].l)//情况1,则要更新最短和次短路径的两个记录{if(dis[edge[i].v][0]<INF){dis[edge[i].v][1] = dis[edge[i].v][0];num[edge[i].v][1] = num[edge[i].v][0];}dis[edge[i].v][0] = node.dis+edge[i].l;num[edge[i].v][0] = num[u][v];tmp.v = edge[i].v,tmp.dis = dis[edge[i].v][0],tmp.num = 0;queue.push(tmp);if(dis[edge[i].v][1]<INF){tmp.v = edge[i].v,tmp.dis = dis[edge[i].v][1],tmp.num = 1;queue.push(tmp);}//}else if(vis[edge[i].v][0] && dis[edge[i].v][0]==node.dis+edge[i].l)}else if(dis[edge[i].v][0]==node.dis+edge[i].l)//情况2,只需在最短路径上加上上个结点的路径数{num[edge[i].v][0] += num[u][v];//}else if(!vis[edge[i].v][1] && dis[edge[i].v][1]>node.dis+edge[i].l)}else if(dis[edge[i].v][1]>node.dis+edge[i].l)//情况3,要更新次短路径的记录{dis[edge[i].v][1] = node.dis+edge[i].l;num[edge[i].v][1] = num[u][v];tmp.v = edge[i].v,tmp.dis = dis[edge[i].v][1],tmp.num = 1;queue.push(tmp);//}else if(vis[edge[i].v][1] && dis[edge[i].v][1]==node.dis+edge[i].l)}else if(dis[edge[i].v][1]==node.dis+edge[i].l)//情况4,只需在次短路径上加上上个结点的路径数{num[edge[i].v][1] += num[u][v];}}}//while(!queue.empty()) queue.pop();return;}int main(){//FILE* fin;//fin = fopen("d.in","r");scanf("%d",&t);//fscanf(fin,"%d",&t);int i,j,k,p;while(t){t--;memset(edge,0,sizeof(edge));memset(head,0,sizeof(head));tot = 0;scanf("%d%d",&n,&m);//fscanf(fin,"%d%d",&n,&m);for(i=1;i<=m;i++){scanf("%d%d%d",&j,&k,&p);//fscanf(fin,"%d%d%d",&j,&k,&p);add(j,k,p,tot,edge,head);}scanf("%d%d",&s,&f);//fscanf(fin,"%d%d",&s,&f);Dijkstra();long ans = num[f][0];if(dis[f][0]==dis[f][1]-1)ans = num[f][0]+num[f][1];printf("%ld\n",ans);}//fclose(fin);return 0;}