单源最短路的综合应用acm


#写在前面

涉及最短路+DFS\二分\DP\拓扑排序

##新年好

https://www.acwing.com/problem/content/1137/

----c++版

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
//在确定了拜访顺序之后,相当于再做5变最短路就好

//如果spfa,5!*5*10^5*k>10^8 可能超时
//可以先预处理,对1abcde六个点做一次单源最短路,
//可得到每个点到其他所有点的最短距离
//之后再dfs查表爆搜
//6*m+5!

//先预处理,再爆搜

#include<cstdio>
#include<queue>

typedef pair<int, int> pll;

const int N=50010, M=200010, inf=0x3f3f3f3f;

int n,m;
int h[N], e[M], w[M], ne[M], idx;
int q[N], dist[6][N];
int source[6];
bool st[N];

void add(int a, int b, int c){
    e[idx]=b, w[idx]=c, ne[idx]=h[a], h[a]=idx++;
}

void dijkstra(int start, int dist[]){
    memset(dist, 0x3f, N*4);
    dist[start]=0;
    memset(st, 0, sizeof st);
    
    priority_queue<pll, vector<pll>, greater<pll>> heap;
    heap.push({0, start});
    
    while(heap.size()){
        auto t=heap.top();
        heap.pop();
        
        int ver=t.second;
        if(st[ver])continue;
        st[ver]=true;
        
        for(int i=h[ver]; ~i; i=ne[i]){
            int j=e[i];
            if(dist[j]>dist[ver]+w[i]){
                dist[j]=dist[ver]+w[i];
                heap.push({dist[j], j});
            }
        }
    }
}

int dfs(int u, int start, int distance){
    if(u>5) return distance;
    int res=inf;
    
    for(int i=1; i<=5; i++)
        if(!st[i]){
            int next=source[i];
            st[i]=true;
            res=min(res, dfs(u+1, i, distance+dist[start][next]));
            st[i]=false;
        }
    return res;
}

int main(){
    scanf("%d%d", &n,&m);
    source[0]=1;
    for(int i=1; i<=5; i++)scanf("%d", &source[i]);
    
    memset(h, -1, sizeof h);
    while(m--){
        int a,b,c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c);
        add(b, a, c);
    }
    
    for(int i=0; i<6; i++)dijkstra(source[i], dist[i]);
    
    memset(st, 0, sizeof st);
    printf("%d\n", dfs(1, 0, 0));
    
    return 0;
}

##通信线路

https://www.acwing.com/problem/content/342/
在这里插入图片描述

----c++版

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#include<deque>

const int N=1010, M=20010;

int n,m,k;
int h[N], e[M], w[M], ne[M], idx;
deque<int> q;
int dist[N];
bool st[N];

void add(int a, int b, int c){
    e[idx]=b, w[idx]=c, ne[idx]=h[a], h[a]=idx++;
}

bool check(int bound){
    memset(st, 0, sizeof st);
    memset(dist, 0x3f, sizeof dist);
    dist[1]=0;
    
    q.push_back(1);
    
    while(q.size()){
        int t=q.front();
        q.pop_front();
        
        if(st[t])continue;
        st[t]=true;
        
        for(int i=h[t]; ~i; i=ne[i]){
            int j=e[i], v=w[i]>bound;
            if(dist[j]>dist[t]+v){
                dist[j]=dist[t]+v;
                if(!v)q.push_front(j);
                else q.push_back(j);
            }
        }
    }
    return dist[n]<=k;
}


int main(){
    cin>>n>>m>>k;
    
    memset(h, -1, sizeof h);
    while(m--){
        int a,b,c;
        cin>>a>>b>>c;
        add(a, b, c); add(b, a, c);
    }
    
    int l=0, r=1e6+1;
    while(l<r){
        int mid=l+r>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    
    if(r==1e6+1)r=-1;
    cout<<r<<endl;
    
    return 0;
}

##道路与航线

https://www.acwing.com/problem/content/344/
在这里插入图片描述
在这里插入图片描述

----c++版

#include<iostream>
#include<algorithm>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>

#define x first
#define y second

using namespace std;
//这题spfa会被卡
//单源最短路+拓扑排序

const int N=25010, M=150010, inf=0x3f3f3f3f;

typedef pair<int, int> pii;

int n, mr, mp, S;
int h[N], e[M], w[M], ne[M], idx;
int id[N];
vector<int> block[N];
int dist[N], din[N];//距离, 入度
bool st[N];
int bcnt;
queue<int> q;

void add(int a, int b, int c){
    e[idx]=b, w[idx]=c, ne[idx]=h[a], h[a]=idx++;
}

void dfs(int u, int bid){
    id[u]=bid;
    block[bid].push_back(u);
    
    for(int i=h[u]; ~i; i=ne[i]){
        int j=e[i];
        if(!id[j])dfs(j, bid);
    }
}

void dijkstra(int bid){
    priority_queue<pii, vector<pii>, greater<pii>> heap;
    
    for(auto ver: block[bid])heap.push({dist[ver], ver});
    
    while(heap.size()){
        auto t=heap.top();
        heap.pop();
        
        int ver=t.y, distance=t.x;
        if(st[ver])continue;
        st[ver]=true;
        
        for(int i=h[ver]; ~i; i=ne[i]){
            int j=e[i];
            if(dist[j]>dist[ver]+w[i]){
                dist[j]=dist[ver]+w[i];
                if(id[j]==id[ver])heap.push({dist[j], j});
            }
            
            if(id[j]!=id[ver]&&--din[id[j]]==0)q.push(id[j]);
        }
    }
}

void topsort(){
    memset(dist, 0x3f, sizeof dist);
    dist[S]=0;
    
    for(int i=1; i<=bcnt; i++)
        if(!din[i])q.push(i);
    
    while(q.size()){
        int t=q.front();
        q.pop();
        dijkstra(t);
    }
}

int main(){
    scanf("%d%d%d%d", &n, &mr, &mp, &S);
    memset(h, -1, sizeof h);
    while(mr--){
        int a,b,c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c); add(b, a, c);
    }
    
    for(int i=1; i<=n; i++)
        if(!id[i])
            dfs(i, ++bcnt);
    
    while(mp--){
        int a,b,c;
        scanf("%d%d%d", &a, &b, &c);
        add(a,b,c);
        din[id[b]]++;
    }
    
    topsort();
    
    for(int i=1; i<=n; i++)
        if(dist[i]>inf/2)puts("NO PATH");
        else printf("%d\n", dist[i]);
    
    return 0;
}

##最优贸易

https://www.acwing.com/problem/content/343/

绝大多数DP可以看成是拓扑图上的最短路问题

启发:如果DP问题的依赖关系存在正环,可以通过最短路的方式求解
在这里插入图片描述

----c++版

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;

const int N=100010, M=2000010;//无向边+反向图

int n,m;
int w[N];
int hs[N], ht[N], e[M], ne[M], idx;
int dmin[N], dmax[N];
bool st[N];
int q[N];

void add(int h[], int a, int b){
    e[idx]=b, ne[idx]=h[a], h[a]=idx++;
}

void spfa(int h[], int dist[], int type){
    int hh=0, tt=1;
    if(type==0){
        //求dmin
        memset(dist, 0x3f, sizeof dmin);//sizeof 后面不能写dist,dist是一个指针
        dist[1]=w[1];
        q[0]=1;
    }
    else{
        memset(dist, -0x3f, sizeof dmax);
        dist[n]=w[n];
        q[0]=n;
    }
    
    while(hh!=tt){
        int t=q[hh++];
        if(hh==N)hh=0; 
        
        st[t]=false;
        for(int i=h[t]; ~i; i=ne[i]){
            int j=e[i];
            if(type==0 && dist[j]>min(dist[t], w[j])|| type==1&& dist[j]<max(dist[t], w[j])){
                if(type==0)dist[j]=min(dist[t], w[j]);
                else dist[j]=max(dist[t], w[j]);
                
                if(!st[j]){
                    q[tt++]=j;//循环队列
                    if(tt==N)tt=0;
                    st[j]=true;
                }
            }
        }
    }
}

int main(){
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++)scanf("%d", &w[i]);
    
    memset(hs, -1, sizeof hs);
    memset(ht, -1, sizeof ht);
    
    while(m--){
        int a,b,c;
        scanf("%d%d%d", &a, &b, &c);
        add(hs, a, b), add(ht, b, a);
        if(c==2)add(hs, b, a), add(ht, a, b);
    }
    
    spfa(hs, dmin, 0);
    spfa(ht, dmax, 1);
    
    int res=0;
    for(int i=1; i<=n; i++) res=max(res, dmax[i]-dmin[i]);
    
    printf("%d\n", res);
    
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值