日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ACM入门之【图论习题】

發布時間:2025/3/20 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ACM入门之【图论习题】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • P5318 【深基18.例3】查找文獻【★ 圖的遍歷】
  • P3916 圖的遍歷【★★ 求每一個點可以到達的最大的點 反向建圖】
  • P1113 雜務【★ ★ 拓撲排序 求完成所有雜務所需的最短時間】
  • P4017 最大食物鏈計數【★ ★ 拓撲排序 求鏈數】
  • P1807 最長路【★ ★ 最長路】
  • P2853 [USACO06DEC]Cow Picnic S【★ 圖的遍歷】
  • P3371 【模板】單源最短路徑(弱化版)【★ 最短路】
  • P1629 郵遞員送信【★★ 一去一回的最短路 反向建圖】
  • P4779 【模板】單源最短路徑(標準版)【★ 最短路】
  • P1144 最短路計數【★★ 統計最短路的數量】
  • P3366 【模板】最小生成樹【★ 最小生成樹】
  • P2872 [USACO07DEC]Building Roads S【★★ 最小生成樹】
  • P1991 無線通訊網【★★ 最小生成樹】
  • P1396 營救【★★ 最小生成樹 讓一個點到另一個點的最大值最小】
  • P2121 拆地毯【★★ 最小生成樹的變種】
  • P1194 買禮物【★★ 最小生成樹】
  • P1195 口袋的天空【★★ 最小生成樹】

P5318 【深基18.例3】查找文獻【★ 圖的遍歷】


考察的就是基礎的圖的遍歷。

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; vector<int>ve[N]; int n,m,st[N]; void dfs(int u) {cout<<u<<" ";st[u]=1;for(int i=0;i<ve[u].size();i++) if(!st[ve[u][i]]) dfs(ve[u][i]); } void bfs(int u) {memset(st,0,sizeof st);queue<int>q; q.push(u); st[u]=1;while(q.size()){u=q.front(); q.pop();cout<<u<<" ";for(int i=0;i<ve[u].size();i++) if(!st[ve[u][i]]) q.push(ve[u][i]),st[ve[u][i]]=1;} } int main(void) {cin>>n>>m;for(int i=0;i<m;i++){int a,b; scanf("%d%d",&a,&b);ve[a].push_back(b);}for(int i=1;i<=n;i++) sort(ve[i].begin(),ve[i].end());//排序dfs(1);puts("");bfs(1);return 0; }

P3916 圖的遍歷【★★ 求每一個點可以到達的最大的點 反向建圖】


求一個點到最大的點,等價于最大的點到它可以到達的點。
故我們可以反向建圖。從大到小枚舉所有的點,如果該點遍歷過了,說明有一個更大的點之前來過(因為我們是先枚舉大結點),故遍歷過的可以不用遍歷。那么總的時間復雜度就是線性的O(m),完全可以過。

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int h[N],e[N],ne[N],idx; int st[N],ans[N],n,m; void add(int a,int b) {e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void dfs(int u,int maxv) {ans[u]=maxv;st[u]=1;for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];if(!st[j]) dfs(j,max(maxv,j));//沒有遍歷過} } int main(void) {memset(h,-1,sizeof h);cin>>n>>m;for(int i=0;i<m;i++){int a,b; scanf("%d%d",&a,&b);add(b,a);//反向建圖}for(int i=n;i>=1;i--) if(!st[i]) dfs(i,i);//從大到小枚舉for(int i=1;i<=n;i++) cout<<ans[i]<<" ";return 0; }

P1113 雜務【★ ★ 拓撲排序 求完成所有雜務所需的最短時間】


比較容易的想到的是拓撲排序。這好像是拓撲排序的一個非常經典的模型。
但問題是如何求,不難想到的是答案就是最晚的點的結束時間。

例:A完成需要先完成B,C。 故A結束的時間=A需要花費的時間+max(B,C)花費的時間

#include<bits/stdc++.h> using namespace std; const int N=1e5*6+10; typedef long long int LL; int h[N],e[N],ne[N],idx; LL w[N],st[N],cnt[N],f[N],n,ans; void add(int a,int b) {e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void topsort() {queue<int>q;for(int i=1;i<=n;i++) if(!cnt[i]) q.push(i),st[i]=1;while(q.size()){int u=q.front(); q.pop();for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];f[j]=max(f[j],w[u]);//求需要完成的先前任務的最大時間if(--cnt[j]==0) {if(!st[j]) q.push(j),st[j]=1,w[j]+=f[j];};}}for(int i=1;i<=n;i++) ans=max(ans,w[i]);//枚舉所有的點,存最晚結束的時間cout<<ans; } int main(void) {memset(h,-1,sizeof h);cin>>n;for(int i=1;i<=n;i++){int x,id;cin>>id>>x;w[id]=x;while(cin>>x,x) add(x,id),cnt[id]++;}topsort();return 0; }

P4017 最大食物鏈計數【★ ★ 拓撲排序 求鏈數】


既然 食物鏈中的生物 可以看成 節點,那么 最佳生產者 的入度一定為 0, 而 最佳消費者 的出度也為 0。

例子:B->A, C->A, 故以A為終點的條數等于 到B點的條數+到C點的條數。這是一個遞推累加的過程。

#include<bits/stdc++.h> using namespace std; typedef long long int LL; const int N=1e5*5+10; const int mod=80112002; int h[N],e[N],ne[N],idx; int st[N],in[N],out[N],n,m; LL sum[N],ans; void add(int a,int b) {e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void topsort() {queue<int>q;for(int i=1;i<=n;i++) if(in[i]==0) q.push(i),st[i]=1,sum[i]=1;while(q.size()){int u=q.front(); q.pop();for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];sum[j]=(sum[j]+sum[u])%mod;if(--in[j]==0){if(!st[j]) q.push(j),st[j]=1;}}} } int main(void) {memset(h,-1,sizeof h);cin>>n>>m;for(int i=0;i<m;i++){int a,b; scanf("%d%d",&a,&b);add(a,b);out[a]++,in[b]++;}topsort();for(int i=1;i<=n;i++) if(out[i]==0) ans=(ans+sum[i])%mod;//是一條鏈的結尾cout<<ans;return 0; }

P1807 最長路【★ ★ 最長路】


傳統的是最短路,那么如何求最長路呢?只需將邊權乘以(-1) 就變成了求最短路。
最后結果記得再乘以(-1)回來就是結果。

#include<bits/stdc++.h> using namespace std; const int N=1e5*5+10; int h[N],e[N],w[N],ne[N],idx; int st[N],dist[N],n,m; void add(int a,int b,int c) {e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; } void spfa() {memset(dist,0x3f,sizeof dist);dist[1]=0;queue<int>q; q.push(1);st[1]=1;while(q.size()){int u=q.front(); q.pop();st[u]=0;for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];if(dist[j]>dist[u]+w[i]){dist[j]=dist[u]+w[i];if(!st[j]) q.push(j),st[j]=1;}}} } int main(void) {memset(h,-1,sizeof h);cin>>n>>m;for(int i=0;i<m;i++){int a,b,c; scanf("%d%d%d",&a,&b,&c);add(a,b,-c);}spfa();if(dist[n]==0x3f3f3f3f) puts("-1");else cout<<-dist[n];return 0; }

P2853 [USACO06DEC]Cow Picnic S【★ 圖的遍歷】


對于每一個奶牛所在的農場遍歷一遍圖。
吐過最后某個農場的計數是k則累加即可。

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; vector<int>ve[N]; int st[N],cnt[N],a[N],k,n,m; void dfs(int u) {cnt[u]++,st[u]=1;for(int i=0;i<ve[u].size();i++) if(!st[ve[u][i]]) dfs(ve[u][i]); } int main(void) {cin>>k>>n>>m;for(int i=1;i<=k;i++) cin>>a[i];for(int i=0;i<m;i++){int a,b; cin>>a>>b;ve[a].push_back(b); }for(int i=1;i<=k;i++){memset(st,0,sizeof st);dfs(a[i]);}int ans=0;for(int i=1;i<=n;i++) if(cnt[i]==k) ans++;cout<<ans;return 0; }

P3371 【模板】單源最短路徑(弱化版)【★ 最短路】

#include<bits/stdc++.h> using namespace std; typedef pair<int,int> pii; const int N=1e4+10; const int M=1e5*5+10; int h[N],e[M],ne[M],w[M],idx; int st[N],dist[N],n,m,s; void add(int a,int b,int c) {e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; } void Dijkstra(int s) {for(int i=1;i<=n;i++) dist[i]=(1ll<<31)-1;dist[s]=0;priority_queue<pii,vector<pii>,greater<pii> >q; q.push({0,s});while(q.size()){auto temp=q.top(); q.pop();int u=temp.second;if(st[u]) continue;st[u]=1;for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];if(dist[j]>dist[u]+w[i]){dist[j]=dist[u]+w[i];q.push({dist[j],j});}}} } int main(void) {memset(h,-1,sizeof h);scanf("%d%d%d",&n,&m,&s);for(int i=1;i<=m;i++){int a,b,c; scanf("%d%d%d",&a,&b,&c);add(a,b,c);}Dijkstra(s);for(int i=1;i<=n;i++) cout<<dist[i]<<" "; }

P1629 郵遞員送信【★★ 一去一回的最短路 反向建圖】


問題在于如何求每一個點回去的時候的最短路。
考慮到回去的最短路,故反向建圖這樣就可以正著跑了。

#include<bits/stdc++.h> using namespace std; const int N=1e5*3+10; typedef pair<int,int> PII; int h[N],e[N],w[N],ne[N],idx; int dist[N],st[N],n,m; void add(int a,int b,int c) {e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; } void Dijkstra(int x) {memset(dist,0x3f,sizeof dist);memset(st,0,sizeof st);dist[x]=0;priority_queue<PII,vector<PII>,greater<PII> >q; q.push({0,x});while(q.size()) {auto temp=q.top(); q.pop();int u=temp.second;if(st[u]) continue;st[u]=1;for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];if(dist[j]>dist[u]+w[i]){dist[j]=dist[u]+w[i];q.push({dist[j],j});}}} } int main(void) {memset(h,-1,sizeof h);cin>>n>>m;for(int i=0;i<m;i++){int a,b,c; scanf("%d%d%d",&a,&b,&c);add(a,b,c);add(b+n,a+n,c);//反向建圖}Dijkstra(1);int sum=0;for(int i=2;i<=n;i++) sum+=dist[i];Dijkstra(1+n);for(int i=2;i<=n;i++) sum+=dist[i+n];cout<<sum<<endl;return 0; }

P4779 【模板】單源最短路徑(標準版)【★ 最短路】

#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<map> using namespace std; const int N=1e5+10; const int M=1e5*2+10; typedef pair<int,int> PII; int h[N],e[M],ne[M],w[M],idx; int dist[N]; bool st[N]; int n,m,s; void add(int a,int b,int c) {e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; } void spfa(int s) {memset(dist,0x3f,sizeof dist);dist[s]=0;st[s]=true;queue<int> q; q.push(s);while(q.size()){int t=q.front(); q.pop();st[t]=false;for(int i=h[t];i!=-1;i=ne[i]){int j=e[i];if(dist[j]>dist[t]+w[i]){dist[j]=dist[t]+w[i];if(!st[j]) q.push(j),st[j]=true;}}} } int main(void) {memset(h,-1,sizeof h);scanf("%d%d%d",&n,&m,&s);while(m--){int a,b,c; scanf("%d%d%d",&a,&b,&c);add(a,b,c);}spfa(s);for(int i=1;i<=n;i++) cout<<dist[i]<<" ";cout<<endl;return 0; }

P1144 最短路計數【★★ 統計最短路的數量】

#include<bits/stdc++.h> using namespace std; const int N=1e6+10; const int M=1e6*4+10; const int mod=100003; int h[N],e[M],ne[M],idx; int cnt[N],dist[N],n,m; void add(int a,int b) {e[idx]=b,ne[idx]=h[a],h[a]=idx++;} void bfs() {memset(dist,0x3f,sizeof dist);dist[1]=0,cnt[1]=1;queue<int>q; q.push(1);while(q.size()){int u=q.front(); q.pop();for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];if(dist[j]>dist[u]+1){dist[j]=dist[u]+1;cnt[j]=cnt[u];q.push(j);}else if(dist[j]==dist[u]+1) {cnt[j]=(cnt[j]+cnt[u])%mod;}}} } int main(void) {memset(h,-1,sizeof h);cin>>n>>m;for(int i=0;i<m;i++){int a,b; cin>>a>>b;add(a,b),add(b,a);}bfs();for(int i=1;i<=n;i++) cout<<cnt[i]<<endl;return 0; }

P3366 【模板】最小生成樹【★ 最小生成樹】

#include<bits/stdc++.h> using namespace std; const int N=1e4+10; int p[N],n,m; struct node{int a,b,c;}; bool cmp(node a,node b){return a.c<b.c;} vector<node>ve; int find(int x) {if(x!=p[x]) p[x]=find(p[x]);return p[x]; } int f() {int res=0,cnt=0;for(int i=1;i<=n;i++) p[i]=i;sort(ve.begin(),ve.end(),cmp);for(int i=0;i<ve.size();i++){int a=ve[i].a,b=ve[i].b,c=ve[i].c;if(find(a)!=find(b)){p[find(a)]=find(b);res+=c;cnt++;}}if(cnt==n-1) return res;else return -1; } int main(void) {cin>>n>>m;while(m--){int a,b,c; cin>>a>>b>>c;ve.push_back({a,b,c});}int ans=f();if(ans==-1) puts("orz");else cout<<ans;return 0; }

P2872 [USACO07DEC]Building Roads S【★★ 最小生成樹】

#include<bits/stdc++.h> using namespace std; const int N=1e4+10; typedef pair<double,double> PII; struct node {int a,b;double c; }; bool cmp(node a,node b){return a.c<b.c;} int n,m,p[N]; vector<node>ve; vector<PII>a; int find(int x) {if(x!=p[x]) p[x]=find(p[x]);return p[x]; } double get(PII a,PII b) {double x=(a.first-b.first)*(a.first-b.first);double y=(a.second-b.second)*(a.second-b.second);return sqrt(x+y); } void solve() {double ans=0;sort(ve.begin(),ve.end(),cmp);for(int i=0;i<ve.size();i++)//最小生成樹{int a=ve[i].a,b=ve[i].b;double c=ve[i].c;if(find(a)==find(b)) continue;p[find(a)]=find(b);ans+=c;}printf("%.2lf",ans); } int main(void) {cin>>n>>m;for(int i=0;i<n;i++){double x,y; cin>>x>>y;a.push_back({x,y});}for(int i=1;i<=n;i++) p[i]=i;for(int i=0;i<m;i++){int a,b; cin>>a>>b;p[find(a)]=find(b);}for(int i=0;i<n;i++)for(int j=i+1;j<n;j++)//存所有的邊{double c=get(a[i],a[j]);ve.push_back({i+1,j+1,c});}solve();return 0; }

P1991 無線通訊網【★★ 最小生成樹】


也就是說衛星電話是無需距離的。
我們先構造一個最小生成樹,然后再減邊。讓其用衛星電話。
例如: 3給衛星電話 可以減2條邊

#include<bits/stdc++.h> using namespace std; typedef pair<int,int> PII; const int N=1e5+10; struct node{int a,b;double c;}; bool cmp(node a,node b){return a.c<b.c;} int m,n,p[N]; vector<node>ve; vector<PII>a; int find(int x) {if(x!=p[x]) p[x]=find(p[x]);return p[x]; } double get(PII a,PII b) {int x=(a.first-b.first)*(a.first-b.first);int y=(a.second-b.second)*(a.second-b.second);return sqrt(x+y); } void sovle() {for(int i=1;i<=n;i++) p[i]=i;vector<double>s;sort(ve.begin(),ve.end(),cmp);for(int i=0;i<ve.size();i++){int a=ve[i].a,b=ve[i].b;double c=ve[i].c;if(find(a)==find(b)) continue;s.push_back(c);p[find(a)]=find(b);}sort(s.begin(),s.end());printf("%.2lf",s[s.size()-1-(m-1)]); } int main(void) {cin>>m>>n;for(int i=0;i<n;i++) {int x,y; cin>>x>>y;a.push_back({x,y});}for(int i=0;i<n;i++)for(int j=i+1;j<n;j++){double c=get(a[i],a[j]);ve.push_back({i+1,j+1,c});}sovle();return 0; }

P1396 營救【★★ 最小生成樹 讓一個點到另一個點的最大值最小】

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; struct node{int a,b,c;}; bool cmp(node a,node b){return a.c<b.c;} int p[N],n,m,s,t; vector<node>ve; int find(int x) {if(x!=p[x]) p[x]=find(p[x]);return p[x]; } void solve() {for(int i=1;i<=n;i++) p[i]=i;sort(ve.begin(),ve.end(),cmp);for(int i=0;i<m;i++){int a=ve[i].a,b=ve[i].b,c=ve[i].c;p[find(a)]=find(b);if(find(s)==find(t)) //說明聯通了{cout<<c;return;}} } int main(void) {cin>>n>>m>>s>>t;for(int i=0;i<m;i++){int a,b,c; cin>>a>>b>>c;ve.push_back({a,b,c});}solve();return 0; }

P2121 拆地毯【★★ 最小生成樹的變種】

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int p[N],n,m,k; struct node{int a,b,c;}; bool cmp(node a,node b){return a.c>b.c;}//從大到小排 vector<node>ve; int find(int x) {if(x!=p[x]) p[x]=find(p[x]);return p[x]; } void solve() {for(int i=1;i<=n;i++) p[i]=i;sort(ve.begin(),ve.end(),cmp);int cnt=0,ans=0;for(int i=0;i<ve.size();i++){int a=ve[i].a,b=ve[i].b,c=ve[i].c;if(find(a)==find(b)) continue;ans+=c,cnt++;p[find(a)]=find(b);if(cnt>=k) break;}cout<<ans; } int main(void) {cin>>n>>m>>k;for(int i=0;i<m;i++){int a,b,c; cin>>a>>b>>c;ve.push_back({a,b,c});}solve();return 0; }

P1194 買禮物【★★ 最小生成樹】

#include<bits/stdc++.h> using namespace std; const int N=1010; int price,n,g[N][N],p[N]; struct node{int a,b,c;}; vector<node>ve; bool cmp(node a,node b){return a.c<b.c;} int find(int x) {if(x!=p[x]) p[x]=find(p[x]);return p[x]; } void solve() {for(int i=1;i<=n;i++) p[i]=i;sort(ve.begin(),ve.end(),cmp);int cnt=1,w=price;for(int i=0;i<ve.size();i++){int a=ve[i].a,b=ve[i].b,c=ve[i].c;if(find(a)==find(b)) continue;if(c>=price) continue;//也就是說不如直接買w+=c,cnt++;p[find(a)]=find(b);}cout<<(n-cnt)*price+w;//(n-cnt) 就是還沒買的 } int main(void) {cin>>price>>n;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) cin>>g[i][j];for(int i=1;i<=n;i++)for(int j=i;j<=n;j++)if(g[i][j]) ve.push_back({i,j,g[i][j]});solve();return 0; }

P1195 口袋的天空【★★ 最小生成樹】


先構造最小生成樹,再減最大的邊讓其變成k個連通塊

#include<bits/stdc++.h> using namespace std; const int N=1e5+10; struct node{int a,b,c;}; int p[N],n,m,k,ans; bool cmp(node a,node b){return a.c<b.c;} vector<node>ve; int find(int x) {if(x!=p[x]) p[x]=find(p[x]);return p[x]; } void kruskal() {for(int i=1;i<=n;i++) p[i]=i;sort(ve.begin(),ve.end(),cmp);vector<int>s;int ans=0;for(int i=0;i<ve.size();i++){int a=ve[i].a,b=ve[i].b,c=ve[i].c;if(find(a)==find(b)) continue;p[find(a)]=find(b);s.push_back(c);ans+=c;}sort(s.begin(),s.end());reverse(s.begin(),s.end());//讓其從大到小排序map<int,int>mp;for(int i=1;i<=n;i++) mp[find(i)]++;//連通塊的數量if(mp.size()>k||n<k) puts("No Answer");else{k=k-mp.size();//需要減幾條邊for(int i=0;i<k;i++) ans-=s[i];cout<<ans;} } int main(void) {cin>>n>>m>>k;for(int i=0;i<m;i++){int a,b,c; cin>>a>>b>>c;ve.push_back({a,b,c});}kruskal();return 0; }

總結

以上是生活随笔為你收集整理的ACM入门之【图论习题】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。