bzoj1598: [Usaco2008 Mar]牛跑步
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1598
思路:裸的k短路,直接用A*+堆即可
A*就是引入一个估价函数h(x)=f(x)+g(x)
优先选择估价小的去搜索
f(x)就是当前到的x已花费代价
g(x)就是估计x到终点还要多少代价
这里f(x)就是出发点S到x的距离
g(x)就是x到终止点T的距离
g(x)可以再反图上跑一遍dijksta+heap预处理出来
过程就是一个类bfs过程
首先把S扔进优先队列
从优先队列中取出f(x)最小的点x
如果x==T,那么就又找到了一条路径,如果已经到T K次了,那么就找到了K短路
否则就把相邻的点扩展进来,加入优先队列中。
如果s==t,k要加1
时间复杂度:O(玄学) O(nk)
一个n元环就把它卡废了....
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define PI pair<int,int> #define fi first #define se second #define mp(a,b) make_pair(a,b) const int maxn=100010,maxm=100010; using namespace std; int n,m,K,cnt[maxn],pre[maxm],now[maxn],son[maxm],val[maxm],tot,dis[maxn],S,T,inf,ans[maxn]; void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;} priority_queue<PI,vector<PI>,greater<PI> > q; struct Topp_graph{ int pre[maxm],now[maxn],son[maxm],val[maxm],tot; void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;} void dijkstra(){ memset(dis,63,sizeof(dis)),inf=dis[0]; dis[T]=0,q.push(mp(0,T)); while (!q.empty()){ int x=q.top().se,d=q.top().fi; q.pop(); for (int y=now[x];y;y=pre[y]) if (dis[son[y]]>d+val[y]){ dis[son[y]]=d+val[y]; q.push(mp(dis[son[y]],son[y])); } } while (!q.empty()) q.pop(); } }opp; void Astar(){ memset(ans,-1,sizeof(ans)); if (dis[S]==inf) return; q.push(mp(dis[S],S)); while (!q.empty()){ int x=q.top().se,d=q.top().fi; cnt[x]++,q.pop(); if (x==T) ans[cnt[x]]=d; for (int y=now[x];y;y=pre[y]) if (cnt[x]<=K) q.push(mp(dis[son[y]]+d-dis[x]+val[y],son[y])); } } int main(){ scanf("%d%d%d",&n,&m,&K),S=n,T=1; for (int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z),add(x,y,z),opp.add(y,x,z); opp.dijkstra(),Astar(); for (int i=1;i<=K;i++) printf("%d\n",ans[i]); //for (int i=1;i<=n;i++) printf("%d\n",dis[i]); return 0; }