题目链接:oj22854
题目:
题意:给出N个点,M条无向边,让你从中找出k条从源点1到终点N的最短路,可以重复走某个点(假设满足最短距离最小的话),
最后问:走完k条最短路,总距离是多少?
题解:刚开始用了优先队列加最短路,wa了。
看完标程加niubi队友讲解,其实就是个优先队列加bfs。
代码写的很暴力,但不加剪枝的话,爆内存。
我们可以这样剪枝,当某一点走的次数大于k次,说明此路径一定不是最优的。为什么呢?
1,我们可以先这样假设,存在一条最短路(min)是最小的,并且满足以后的k-1条"最短路"都在这条最短路(min)上的某一条边往返,那么此时某一点是不是最多走k次。
2,我们再假设,存在一条最短路(min)是最小的,并且以后的k-1条"最短路"不一定都在这条最短路(min)上的某一条边往返,那么此时,任何一个点都不能走k次,因为会被其它更短的路径给替代了。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct node{
int v,edge;
};
vector<node> G[900];
struct NODE{
int val;///到达此点的价值
int index;///点
bool operator < (const NODE &a) const{
return val>a.val;///优先队列按小顶堆排
}
};
priority_queue<NODE> que;
int book[900];
int main()
{
memset(book,0,sizeof(book));
int k,n,m;
scanf("%d%d%d",&k,&n,&m);
int num=k;
for(int i=1;i<=m;i++)
{
int s,t,w;
scanf("%d%d%d",&s,&t,&w);
G[s].push_back({t,w});
G[t].push_back({s,w});
}
int ans=0;
que.push({0,1});///先放入价值为0,顶点为1
while(!que.empty())
{
NODE item=que.top();
que.pop();
///剪枝
book[item.index]++;///到达此点后++
if(book[item.index]>num) continue;///如果某一点走的次数大于k次,说明此路径不满足最优
if(item.index==n){///到达终点
ans+=item.val;
k--;
continue;
}
if(!k) break;
int len=G[item.index].size();
for(int i=0;i<len;i++){///push与item.index的邻接点
NODE t;
t.val=item.val+G[item.index][i].edge;
t.index=G[item.index][i].v;
que.push(t);
}
}
printf("%d\n",ans);
return 0;
}
我的标签:做个有情怀的程序员。