题目链接:点击查看
题目大意:给出一个 n 个点,m 条边的无向图,需要求出图中第 k 短的路径
题目分析:k 是 400,本来以为是需要思考 k * n 或 k * m 的算法,搞了半天最后原来是 k^3 的算法。。
首先考虑,先把图中前 k 小的边全部拿出来,比较显然的是,答案最坏也不可能超过第 k 小的这条边
然后对于这 k 条边涉及到的 2 * k 个点单独拎出来跑弗洛伊德,然后将 k * ( k - 1 ) / 2 条路径的权值排个序求第 k 小就是答案了
妙啊
2020.12.3UPDATE:
用bfs也可以做,昨天想到用bfs了,只不过不会对路径判重,今天看题解受到启发,可以将无向边拆成两条有向边,然后求第 2 * k 小的路径即是答案
兴致勃勃写了一发 n * k * logn 的算法,交上去 MLE 了,说明暴力扩展是不太合适的,所以考虑优化
可以将邻接表中的所有邻边按照权值排序,并且对于每条边来说,之前记录的是 ( st , ed ),现在我们需要记录一个中间点 x,也就是 ( st , x , ed ),满足最后一条边是 x -> ed,这样还看不出来有什么好处,但是我们实际上记录的是 ( st , x , index ),index 指的是 x 的邻接表中的第 index 个元素,自然可以表示出 ed 了,并且还有一个最大的好处就是,在扩展的时候,将 st -> x -> index 这条边撤回,改成 st -> x -> index+1 一定是最优的,所以扩展状态的时候就有两种途径了:
- ( st , x , index )扩展到(st , x , index + 1 )
- ( st , x , index )扩展到(st , ed , 0),这里的 ed 就是 x 的第 index 个元素表示的点
因为每次只扩展两个状态,所以 bfs 的复杂度是 O( n ) ,因为需要对每条边排序,所以总时间复杂度是 O( nlogn ) 的
代码:
Floyd:
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const LL inf=0x3f3f3f3f3f3f3f3f;
const int N=1e3+100;
struct Edge
{
int u,v,w;
void input()
{
scanf("%d%d%d",&u,&v,&w);
}
bool operator<(const Edge& t)const
{
return w<t.w;
}
}edge[N*N];
vector<int>node;
LL maze[N][N];
void floyd(int n)
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
maze[i][j]=min(maze[i][j],maze[i][k]+maze[k][j]);
}
int get_id(int x)
{
return lower_bound(node.begin(),node.end(),x)-node.begin()+1;
}
void discreate()
{
sort(node.begin(),node.end());
node.erase(unique(node.begin(),node.end()),node.end());
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.ans.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
edge[i].input();
sort(edge+1,edge+1+m);
for(int i=1;i<=k;i++)
{
node.push_back(edge[i].u);
node.push_back(edge[i].v);
}
discreate();
n=node.size();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
maze[i][j]=i==j?0:inf;
for(int i=1;i<=k;i++)
{
int u=get_id(edge[i].u),v=get_id(edge[i].v);
maze[u][v]=maze[v][u]=edge[i].w;
}
floyd(n);
vector<LL>ans;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
ans.push_back(maze[i][j]);
nth_element(ans.begin(),ans.begin()+k-1,ans.end());
printf("%lld\n",ans[k-1]);
return 0;
}
bfs:
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e6+100;
struct Node
{
int st,ed,id;
LL w;
bool operator<(const Node& t)const
{
return w>t.w;
}
};
set<pair<int,int>>vis;//st,ed
vector<pair<int,int>>node[N];
priority_queue<Node>q;
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.ans.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
while(m--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
node[u].emplace_back(w,v);
node[v].emplace_back(w,u);
}
for(int i=1;i<=n;i++)
{
sort(node[i].begin(),node[i].end());
q.push({i,i,0,node[i][0].first});
vis.emplace(i,i);
}
k*=2;
while(q.size())
{
auto cur=q.top();
q.pop();
if(cur.id+1<node[cur.ed].size())
q.push({cur.st,cur.ed,cur.id+1,cur.w-node[cur.ed][cur.id].first+node[cur.ed][cur.id+1].first});
if(vis.count(make_pair(cur.st,node[cur.ed][cur.id].second)))
continue;
vis.emplace(cur.st,node[cur.ed][cur.id].second);
if(--k==0)
return 0*printf("%lld\n",cur.w);
q.push({cur.st,node[cur.ed][cur.id].second,0,cur.w+node[node[cur.ed][cur.id].second][0].first});
}
return 0;
}