超超超冷门的算法之最短路径生成树(SPT)
什么是最短路径生成树?
画图:
假设我们的源点是 C,那么,最短路径生成树就是以 C 为源点的到达每个点的路径最短的生成树(简单无向带权连同图)。
我们直接按照贪心思路求出一个最短路径生成树(按照优先选边权小的,就是
可以发现,选出来的路径是:C E B A。如果用
如果把走到的边都选中,那么选中的边就是一个最短路径生成树了。
但是,这张图不止这样的路径,还有许多的路径也可以达到同样的效果,例如:C A B,然后C E,或者 C E B,然后C A。如果在更加复杂的图里面,甚至会更多,所以,我们要根据题目的要求来求。
我们先来看第一道题。
CF545E Paths and Trees
思路
这题一看,和最短路径生成树很像,但是要求权值总和最小,我们再来观察上图:
C E B A 的权值总和:
C A B,然后C E 的权值总和:
C E B,然后C A 的权值总和:
C A B E 的权值总和:
不同的最短路径生成树的权值总和是不一样的。
然后,题目还说要输出边的编号。
那么,我们在储存边的时候,要多使用一个
在判断成功的时候,我们记录
当然,我们还要判断是不是等于,因为如果路径等于,权值不一定等于,上方的图已经说明了这点。
那么,如果等于,并且权值更优的话,则也要记录,但是不要重复加入队列当中,因为队列记录的是路径,而不是权值总和。这样只会让爆空间的可能新更大。
如果将所有的点都更新了,则直接循环每一个点,只要不是起点,就加上
Code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+5,inf=1e18;
int n,m,s,dis[N],pre[N],val[N];
bool vis[N];
struct edge{
int v,w,id;
};
vector<edge> g[N];
struct no{
int id,w;
bool operator <(const no& rhs) const
{
return w>rhs.w;
}
};
void dijkstra()
{
for(int i=1;i<=n;++i)
{
dis[i]=inf;
vis[i]=0;
}
priority_queue<no> q;
q.push({s,0});
dis[s]=0;
while(!q.empty())
{
int u=q.top().id;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(auto V:g[u])
{
int v=V.v;
if(vis[v]==0&&dis[v]>dis[u]+V.w)
{
dis[v]=dis[u]+V.w;
pre[v]=V.id;
q.push({v,dis[v]});
}
if(vis[v]==0&&dis[v]==dis[u]+V.w&&V.w<val[pre[v]])
{
pre[v]=V.id;
}
}
}
return;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;++i)
{
int x,y,z;
cin>>x>>y>>z;
g[x].push_back({y,z,i});
g[y].push_back({x,z,i});
val[i]=z;
}
cin>>s;
dijkstra();
int sum=0;
vector<int> ans;
for(int i=1;i<=n;++i)
{
if(i==s) continue;
sum+=val[pre[i]];
ans.push_back(pre[i]);
}
sort(ans.begin(),ans.end());
cout<<sum<<'\n';
for(auto it:ans) cout<<it<<' ';
return 0;
}
CF1076D Edge Deletion
思路
洛谷翻译有误,因为第一句话的说明指的是一棵树,但是这是我们最终的目的,而且
我们还是画一个图理解(第一问)。
假设此时
不难发现,这个图至多有
但是,如果
接下来就是第二问了。
如果
还需要注意如果
Code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+5,inf=1e18;
int n,m,k,dis[N],pre[N],val[N];
bool vis[N];
struct edge{
int v,w,id;
};
vector<edge> g[N];
struct no{
int id,w;
bool operator <(const no& rhs) const
{
return w>rhs.w;
}
};
void dijkstra()
{
for(int i=1;i<=n;++i)
{
dis[i]=inf;
vis[i]=0;
}
priority_queue<no> q;
q.push({1,0});
dis[1]=0;
while(!q.empty())
{
int u=q.top().id;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(auto V:g[u])
{
int v=V.v;
if(vis[v]==0&&dis[v]>dis[u]+V.w)
{
dis[v]=dis[u]+V.w;
pre[v]=V.id;
q.push({v,dis[v]});
}
if(vis[v]==0&&dis[v]==dis[u]+V.w&&V.w<val[pre[v]])
{
pre[v]=V.id;
}
}
}
return;
}
int cnt;
void dfs(int u,int fa)
{
for(auto V:g[u])
{
int v=V.v;
if(pre[v]==V.id&&v!=fa)
{
cnt++;
if(cnt>k) exit(0);
cout<<V.id<<' ';
dfs(v,u);
}
}
return;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=m;++i)
{
int x,y,z;
cin>>x>>y>>z;
g[x].push_back({y,z,i});
g[y].push_back({x,z,i});
val[i]=z;
}
dijkstra();
cout<<min(k,n-1)<<'\n';
if(k) dfs(1,0);
return 0;
}