《算法竞赛进阶指南》图论习题
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; }
升降梯上
把电梯的层数和控制槽的位置作为状态,把各状态提取出再进行连边,跑最短路。
#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; }
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; }
社交网络
用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; }
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; }
以上是关于《算法竞赛进阶指南》图论习题的主要内容,如果未能解决你的问题,请参考以下文章
《算法竞赛进阶指南》-AcWing-91. 最短Hamilton路径-题解