acm.hdu.edu.cn/showproblem.php?pid=6181
我是用次短路板子做的。。初始化得多点不然得超时。
①求次短路的思路是维护到达x点的最小距离和次小距离。(dij和spfa应该都可以,都做一下板子)
② 用A*,即启发式搜索,先求出F(X)即x点到目的点的代价,在求S(x),即初始点到x点的代价,然后找第k小的。用muliset或者优先队列都行,(multiset写了好一会。。)
③ 求出最短路后,枚举。。这个我没敢弄,因为怕超时。O(VE)
* 我A*的理解:一般的搜索都是闭着眼搜索,随便搜索,枚举所有的状态,有的花费巨大且是坑,但是也要试一遍。效率不高。
而A*则预先计算当前状态到目的状态的花费,找最小的试,
贼好。正面计算 初始点到当前状态的话费时,像bfs,但是比bfs高效的原因就是因为前面的就记录(不记录爆搜的话mle)
先计算了D,在遍历F,
#include <bits/stdc++.h>
using namespace std;
/* multiset 或者优先队列,都是可以的,,好像qwq
*/
/*
*/
typedef long long ll;
typedef pair<ll,int> pii;
const long long INF=1e14;
const int maxn=1e5;
struct Node{
int to;ll w;
Node(){};
Node(int _a,ll _b){to=_a;w=_b;};
};
ll dis[maxn];
struct qNode{
int to;
ll w;
qNode(){};
qNode(ll _a,int _b){to=_b;w=_a;};
friend bool operator <(qNode a,qNode b){
return a.w+dis[a.to]<b.w+dis[b.to];// 返回最小的。这个很重要,A*的重点(敲屏幕)
}
};
//记录D(x)
vector<Node>G[maxn];
multiset<qNode>mul;
void add(int u,int v,long long w){
G[u].push_back(Node(v,w));
G[v].push_back(Node(u,w));
}
int k,m;
void init(){
for(int i=0;i<maxn;i++)
G[i].clear();
mul.clear();
}
void dij(int st){
priority_queue<pii,vector<pii>,greater<pii> >q;
for(int i=0;i<maxn;i++)
dis[i]=INF;
dis[st]=0;
q.push(make_pair(0,st));
while(!q.empty()){
pii u=q.top();
//cout<<u.second<<"!!"<<u.first<<endl;
q.pop();
for(int i=0;i<G[u.second].size();i++){
ll d=G[u.second][i].w+u.first;
int to=G[u.second][i].to;
if(d<dis[to]){
dis[to]=d;
q.push(make_pair(dis[to],to));
//cout<<d<<"juli"<<endl;
// cout<<G[u.second][i].w<<"jjjjl"<<endl;
}
}
}
}
void a_star(int st){
mul.insert(qNode(0,st));
k--;
while(!mul.empty()){
qNode u=*mul.begin();
mul.erase(mul.begin());
if(u.to==m){
if(k) k--;
else
{cout<<u.w<<endl;return;}
}
for(int i=0;i<G[u.to].size();i++){
//cout<<G[u.to][i].w+u.w<<endl;
int to=G[u.to][i].to;
mul.insert(qNode(u.w+G[u.to][i].w,to));
}
//cout<<mul.size()<<"@@@"<<endl;
}
}
/*void a_sta(int st){
priority_queue<qNode>q;
q.push(qNode(0,st));
k--;
while(!q.empty()){
qNode u=q.top();
q.pop();
if(u.to==m){
if(k)k--;
else {printf("%lld\n",u.w);return;}
}
for(int i=0;i<G[u.to].size();i++){
ll d=G[u.to][i].w+u.w;
int to=G[u.to][i].to;
q.push(qNode(d,to));
}
}
}*/
int main(){
int t,a,b,n;
ll c;
scanf("%d",&t);
while(t--){
init();
scanf("%d%d",&m,&n);
for(int i=0;i<n;i++){
scanf("%d%d%lld",&a,&b,&c);
add(a,b,c);
}
dij(m);
k=2;
//for(int i=1;i<=m;i++)
//cout<<i<<" "<<dis[i]<<endl;
a_star(1);
}
return 0;
}
次短路板子(dij逼格高,试着求了一下第三短哈哈)
#include <bits/stdc++.h>
using namespace std;
/* 次短路的做法,
① 次短路模板,维护两个值。
② 两次最短路。
③ A*算法
*/
const int maxn=1e5+5;
const long long INF=1e14;
typedef long long ll;
struct Node
{ int to,val;
Node(){};
Node(int _a,int _b){to=_a,val=_b;};
};
vector<Node>G[maxn];
ll dis[maxn];
ll dis2[maxn];
ll dis3[maxn];
void add(int a,int b,ll w){
G[a].push_back(Node(b,w));
G[b].push_back(Node(a,w));
}
void dij(int st){
for(int i=0;i<maxn;i++){
dis[i]=INF;
dis2[i]=INF; //初始化
dis3[i]=INF;
}
priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > >q;
dis[st]=0;
q.push(make_pair(0,st));//入开头元素
while(!q.empty()){
pair<ll,int>u=q.top();
//cout<<u.first<<endl;
q.pop();
if(dis2[u.second]<u.first) continue;
for(int i=0;i<G[u.second].size();i++){
ll d=G[u.second][i].val+u.first;
int to=G[u.second][i].to;
if(d<dis[to]){
swap(d,dis[to]);//最短的。
q.push(make_pair(dis[to],to));
}
if(dis[to]<d&&dis2[to]>d){
swap(d,dis2[to]);
q.push(make_pair(dis2[to],to));
}
/*if(dis3[to]>d&&dis2[to]<d&&dis[to]<d){
dis3[to]=d;
q.push(make_pair(dis3[to],to));
}*/
}
}
}
void init(){
for(int i=0;i<maxn;i++)
G[i].clear();
}
int main()
{ int t,m,n,a,b;
ll c;
scanf("%d",&t);
while(t--){
scanf("%d%d",&m,&n);
init();
for(int i=0;i<n;i++){
scanf("%d%d%lld",&a,&b,&c);
add(a,b,c);
}
//puts("!!!!");
dij(m);
/*for(int i=1;i<=m;i++)
cout<<dis[i]<<" "<<dis2[i]<<endl;*/
printf("%lld\n",dis2[1]);
}
return 0;
}
暴力枚举最短路,大佬的代码,,,先贴了。。
我第一个思路也是这样,但是想的是,维护最短路径,然后每个节点枚举,,而不是这样全图暴力枚举,,只能说大佬。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long int ll;
const int R = 100000+5;
const int INF = 0x3f3f3f3f;
int n,m;
struct Node
{
int v;
int w;
int next;
}edge[R*2];
int head[R];
ll dist1[R];
ll dist2[R];
bool vis[R];
int num;
void init()
{
num = 0;
memset(head,-1,sizeof(head));
for(int i = 1; i <= n; i++)
dist1[i] = dist2[i] = 1e16;
}
void add_edge(int u,int v,int w)
{
edge[num].v = v;
edge[num].w = w;
edge[num].next = head[u];
head[u] = num++;
}
void SPFA(int u,ll *dist)
{
int i,v,w;
queue<int> Q;
memset(vis,false,sizeof(vis));
dist[u] = 0;
vis[u] = true;
Q.push(u);
while(!Q.empty())
{
u = Q.front();
Q.pop();
vis[u] = false;
for(i=head[u];i!=-1;i=edge[i].next)
{
v = edge[i].v;
w = edge[i].w;
if(dist[v] > dist[u] + w)
{
dist[v] = dist[u] + w;
if(!vis[v])
{
vis[v] = true;
Q.push(v);
}
}
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
int i,j,u,v,w;;
init();
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
SPFA(1,dist1);
SPFA(n,dist2);
int flag = 0;
ll ans = 1e16;
for(i=1;i<=n;i++)
{
for(j=head[i];j!=-1;j=edge[j].next)
{
v = edge[j].v;
w = edge[j].w;
//cout<<i<<v<<endl;
ll tem = dist1[i] + dist2[v] + w;
//cout<<tem<<endl;
if(tem > dist1[n] && tem < ans)
{
ans = tem;
}
}
}
printf("%I64d\n",ans);
}
return 0;
}