整理的算法模板合集: ACM模板
目录
∮ 1. 最短路
优先队列最短路
struct Edge
{
ll v,w,next;//v:目的地,w:距离,next:下一个节点
}G[N];
ll head[N],cnt,n,m,s;
ll dis[N];//存距离
inline void addedge(ll u,ll v,ll w)//链式前向星存图
{
cnt++;
G[cnt].w=w;
G[cnt].v=v;
G[cnt].next=head[u];
head[u]=cnt;
}
struct node
{
ll d,u;//d是距离u是起点
bool operator<(const node& t)const//重载运算符
{
return d>t.d;
}
};
inline void Dijkstra()
{
for(register int i=1;i<=n;++i)dis[i]=mod;//初始化
dis[s]=0;
priority_queue<node>q;//堆优化
q.push((node){
0,s});//起点push进去
while(!q.empty())
{
node tmp=q.top();q.pop();
ll u=tmp.u,d=tmp.d;
if(d!=dis[u])continue;//松弛操作剪枝
for(register int i=head[u];i;i=G[i].next)//链式前向星
{
ll v=G[i].v,w=G[i].w;
if(dis[u]+w<dis[v])//符合条件就更新
{
dis[v]=dis[u]+w;
q.push((node){
dis[v],v});//沿着边往下走
}
}
}
}
int main()
{
scanf("%lld %lld %lld",&n,&m,&s);
for(register int i=1;i<=m;++i)
{
ll x,y,z;
scanf("%lld %lld %lld",&x,&y,&z);
addedge(x,y,z);//建图
}
Dijkstra();
for(register int i=1;i<=n;++i)
printf("%lld ",dis[i]);
printf("\n");
return 0;
}
1.1 线段树优化的 D i j k s t r a Dijkstra Dijkstra
时间和内存均是优先队列优化版本的 1 2 \frac{1}{2} 21
int n, m;
struct edge {
int to, w, nxt;
edge() {
}
edge(int t, int ww, int nn) {
to = t, w = ww, nxt = nn;}
}e[maxn << 1];
int head[maxn], k = 0;
void add(int u, int v, int w) {
e[k] = edge(v, w, head[u]); head[u] = k++;}
ll ans[maxn];
struct node {
ll dis; int x;
node() {
}
node(ll d, int xx) {
dis = d, x = xx;}
}dis[maxn << 2];
//建树初始化,主要是编号也要返回所以要先预处理一下
void build(int p, int l, int r) {
if(l == r) {
dis[p].x = l; return;}
int mid = l + r >> 1;
build(p << 1, l, mid); build(p << 1 | 1, mid + 1, r);
dis[p].x = dis[p << 1].x;
}
void change(int p, int l, int r, int x, int y) {
if(l == r) {
dis[p].dis = y; return;}
int mid = l + r >> 1;
if(x <= mid) change(p << 1, l, mid, x, y);
else change(p << 1 | 1, mid + 1, r, x, y);//单点修改的板子操作
if(dis[p << 1].dis < dis[p << 1 | 1].dis) dis[p] = dis[p << 1];
else dis[p] = dis[p << 1 | 1];
}
//因为用距离得到最小,但是需要的是编号,所以返回node
node ask(int p, int l, int r, int ls, int rs) {
if(ls <= l && r <= rs) {
return dis[p];}
int mid = l + r >> 1; node ans = node(inf, 0), tmp;
if(ls <= mid) ans = ask(p << 1, l, mid, ls, rs);
if(rs > mid) {
node tmp = ask(p << 1 | 1, mid + 1, r, ls, rs);
if(ans.dis > tmp.dis) ans = tmp;
}
return ans;
}
int S;
void dij() {
for(int k = 1; k < n; k++) {
//n-1次够用的。虽然我也不知道为什么最后n次跑的比n-1次还要快……
register int u = ask(1, 1, n, 1, n).x;
for(int i = head[u]; ~i; i = e[i].nxt) {
register int v = e[i].to;
if(ans[u] + e[i].w < ans[v]) {
//最短路更新
ans[v] = ans[u] + e[i].w, change(1, 1, n, v, ans[v]);//单点修改
}
}
change(1, 1, n, u, inf);//取出来过后要赋值INF,以免再次取用
}
}
int main() {
memset(head, -1, sizeof head);
n = read(), m = read(), S = read();
for(int u, v, w, i = 1; i <= m; i++) u = read(), v = read(), w = read(), add(u, v, w);
//初始化
for(int i = 1; i <= (n << 2); i++) dis[i].dis = inf;
for(int i = 1; i <= n; i++) ans[i] = inf;
//线段树初始化,dis是线段树,ans是答案
build