《算法竞赛进阶指南》图论习题

Posted judp

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法竞赛进阶指南》图论习题相关的知识,希望对你有一定的参考价值。

前言

    算法竞赛进阶指南图论习题。慢慢刷。

Sightseeing

        这个题求最短路以及比最短路大1的路的条数。关键是次短路如何构成。分析可以发现一个点的次短路一定为相邻点次短路或者最短路构成。所以dijkstra维护最短路和次短路即可。

 

技术图片
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=1e3+10;
const int M=1e4+10;
int head[N],ver[M],edge[M],nex[M],tot=1;
inline void add(int x,int y,int z) {
    ver[++tot]=y,edge[tot]=z,nex[tot]=head[x],head[x]=tot;
}
struct Node {
    bool operator<(const Node &t)const {return d>t.d;}
    Node(int x,int d):x(x),d(d){}
    int x,d;
};
//dis1最短路dis2次短路cnt1最短路数量cnt2次短路数量
int dis1[N],dis2[N],cnt1[N],cnt2[N];
int dijkstra(int s,int t){
    dis1[s]=0;
    cnt1[s]=1;
    priority_queue<Node> q;
    q.push(Node(s,0));
    while(!q.empty()){
        int x=q.top().x,d=q.top().d;q.pop();
        if(d>dis2[x])continue;
        for(int i=head[x];i;i=nex[i]){
            int y=ver[i],len=d+edge[i];
            if(dis1[y]>len){
                dis2[y]=dis1[y];cnt2[y]=cnt1[y];
                dis1[y]=len;cnt1[y]=cnt1[x];
                q.push(Node(y,len));
            }else if(dis1[y]==len)
                cnt1[y]+=cnt1[x];
            else if(dis2[y]>len){
                dis2[y]=len;
                cnt2[y]=dis1[x]==d?cnt1[x]:cnt2[x];
                q.push(Node(y,len));
            }else if(dis2[y]==len)
                cnt2[y]+=dis1[x]==d?cnt1[x]:cnt2[x];
        }
    }
    return cnt1[t]+(dis1[t]+1==dis2[t]?cnt2[t]:0);
}
void init(int n){
    for(int i=1;i<=n;++i){
        head[i]=0;
        dis1[i]=dis2[i]=INF;
        cnt1[i]=cnt2[i]=0;
    }
    tot=1;
}
int main(){
    int T,n,m,s,t,x,y,w;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        init(n);
        for(int i=0;i<m;++i){
            scanf("%d%d%d",&x,&y,&w);
            add(x,y,w);
        }
        scanf("%d%d",&s,&t);
        printf("%d
",dijkstra(s,t));
    }
    return 0;
}
View Code

 

升降梯上

        把电梯的层数和控制槽的位置作为状态,把各状态提取出再进行连边,跑最短路。

技术图片
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=1000*20+10;
const int M=N*20+10;
int head[N],ver[M],edge[M],nex[M],tot=1;
inline void add(int x,int y,int z) {
    ver[++tot]=y,edge[tot]=z,nex[tot]=head[x],head[x]=tot;
}
struct Node {
    bool operator<(const Node &t)const{return d>t.d;}
    Node(int x,int d):x(x),d(d) {}
    int x,d;
};
int dis[N],vis[N];
void dijkstra(int s) {
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[s]=0;
    priority_queue<Node> pq;
    pq.push(Node(s,0));
    while(!pq.empty()) {
        int x=pq.top().x;
        pq.pop();
        if(vis[x])continue;
        vis[x]=1;
        for(int i=head[x]; i; i=nex[i]) {
            int y=ver[i];
            if(dis[y]>dis[x]+edge[i]) {
                dis[y]=dis[x]+edge[i];
                pq.push(Node(y,dis[y]));
            }
        }
    }
}
int n,m,c[30];
inline int encode(int x,int y){return (x-1)*m+y+1;}
void build(){
    for(int i=1;i<=n;++i)
        for(int j=0;j<m;++j)
            for(int k=0;k<m;++k)
                if(i+c[k]>=1&&i+c[k]<=n)
                    add(encode(i,j),encode(i+c[k],k),abs(c[k]*2)+abs(j-k));
}
int main(){
    scanf("%d%d",&n,&m);
    int s,ans=INF;
    for(int i=0;i<m;++i){scanf("%d",c+i);if(c[i]==0)s=i;}
    build();
    dijkstra(encode(1,s));
    for(int i=0;i<m;++i)
        ans=min(ans,dis[encode(n,i)]);
    printf("%d",ans==INF?-1:ans);
    return 0;
}
View Code

 

GF和猫咪的玩具

        简单题,floyd

技术图片
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int mp[110][110];
int main(){
    int n,m,x,y;
    memset(mp,INF,sizeof(mp));
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;++i){
        scanf("%d%d",&x,&y);
        mp[x][y]=1;
        mp[y][x]=1;
    }
    for(int k=1;k<=n;++k)
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
    int ans=0;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            if(mp[i][j]!=INF)ans=max(ans,mp[i][j]);
    printf("%d",ans);
    return 0;
}
View Code

社交网络

        用floyd计算一下两点间最短路条数以及过一个点的最短路条数。

技术图片
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int mp[105][105];
ll cnt[105][105];
int main(){
    int n,m,x,y,c;
    scanf("%d%d",&n,&m);
    memset(mp,0x3f,sizeof(mp));
    for(int i=0;i<m;++i){
        scanf("%d%d%d",&x,&y,&c);
        mp[x][y]=mp[y][x]=min(mp[x][y],c);
        cnt[x][y]=cnt[y][x]=1;
    }
    for(int k=1;k<=n;++k)
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                if(mp[i][j]>mp[i][k]+mp[k][j]){
                    mp[i][j]=mp[i][k]+mp[k][j];
                    cnt[i][j]=cnt[i][k]*cnt[k][j];
                }
                else if(mp[i][j]==mp[i][k]+mp[k][j])
                    cnt[i][j]+=cnt[i][k]*cnt[k][j];
    double ans;
    for(int k=1;k<=n;++k){
        ans=0;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                if(i!=k&&j!=k&&i!=j)
                    ans+=(double)(mp[i][k]+mp[k][j]==mp[i][j]?cnt[i][k]*cnt[k][j]:0)/cnt[i][j];
        printf("%.3f
",ans);
    }
    return 0;
}
View Code

Arctic Network

        kruskal求最小生成树,当联通块的数量等于卫星数量时结束,答案即最后加入的边长度。

技术图片
#include<bits/stdc++.h>
using namespace std;
const int N=600;
struct Edge{
    Edge(int x,int y,int len2):x(x),y(y),len2(len2){}
    bool operator<(const Edge &t){return len2<t.len2;}
    int x,y,len2;
};
int fa[N],x[N],y[N];
int get(int x){return x==fa[x]?x:fa[x]=get(fa[x]);}
int dis2(int i,int j){return (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);}
int main(){
    int t,s,p;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&s,&p);
        for(int i=1;i<=p;++i){
            fa[i]=i;
            scanf("%d%d",x+i,y+i);
        }
        vector<Edge> e;
        for(int i=1;i<=p;++i)
            for(int j=1;j<=p;++j)
                if(i!=j)e.push_back(Edge(i,j,dis2(i,j)));
        sort(e.begin(),e.end());
        double ans;
        for(Edge &t:e){
            int u=get(t.x),v=get(t.y);
            if(u==v)continue;
            fa[u]=v;
            if(--p==s){
                ans=sqrt(t.len2);
                break;
            }
        }
        printf("%.2f
",ans);
    }
    return 0;
}
View Code

以上是关于《算法竞赛进阶指南》图论习题的主要内容,如果未能解决你的问题,请参考以下文章

2021算法竞赛入门班第七节课图论练习题

《算法竞赛进阶指南》0x03差分

《算法竞赛进阶指南》0x32约数 余数之和

《算法竞赛进阶指南》-AcWing-91. 最短Hamilton路径-题解

《算法竞赛进阶指南》-AcWing-91. 最短Hamilton路径-题解

题解|《算法竞赛进阶指南》 Sticks