第1节 连通性强连通、割点和桥 例题
生活随笔
收集整理的這篇文章主要介紹了
第1节 连通性强连通、割点和桥 例题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
NC15707 可達性
題目:
給出一個 0 ≤ N ≤ 105 點數、0 ≤ M ≤ 105 邊數的有向圖,
輸出一個盡可能小的點集,使得從這些點出發能夠到達任意一點,如果有多個這樣的集合,
輸出這些集合升序排序后字典序最小的。
題解:
? 先強連通縮點,變成一個有向無環圖
? 然后在所有入度為0的點集,每一個拿出編號最小的一個點
記錄縮點后的入度
代碼:
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; const int INF = 0x3f3f3f3f; struct node {int v, next; }edge[maxn]; vector<int>p; stack <int> s; int dfn[maxn],low[maxn]; int color[maxn],in[maxn]; int tot,block; int head[maxn],pre[maxn]; int n,m,cnt,C,X; bool vis[maxn]; void add(int from, int to) {edge[++cnt].v=to;edge[cnt].next=head[from];head[from]=cnt; } void tarjan(int u) {dfn[u]=low[u]= ++tot;vis[u]=1;s.push(u);for(int i=head[u];i!=-1;i=edge[i].next) {int v=edge[i].v;if (!dfn[v]) {tarjan(v);low[u]= min(low[u],low[v]);}else if(vis[v]) low[u]=min(low[u],dfn[v]);}if (dfn[u]==low[u]) {block++;int v;do {v=s.top();s.pop();color[v]=block;pre[block]=min(v, pre[block]);//pre保存的是同強連通分量中編號最小點 vis[v]=0;} while (v!=u);} }int main() {cin>>n>>m;memset(head,-1,sizeof(head));memset(pre,INF,sizeof(pre));for(int i=0;i<m;i++){int u,v;scanf("%d%d",&u,&v);add(u,v);}for(int i=1;i<=n;i++){if(!dfn[i]) tarjan(i);}if(block==1){cout <<"1"<< endl; return 0; }for(int i=1;i<=n;i++){for(int j=head[i];j!=-1;j=edge[j].next){int u=color[i];int v=color[edge[j].v];if(u!=v)in[v]++;//記錄入度 }}for(int i=1;i<=block;i++){//此處已經進行完壓縮,壓縮后還有block個點 if(!in[i]) //如果一個點沒有入度 p.push_back(pre[i]);}sort(p.begin(),p.end());cout<<p.size()<<endl;for(int i=0;i<p.size();i++) cout<<p[i]<< " ";cout<<endl;return 0; }NC 19960 [HAOI2006]受歡迎的牛
題目:
? 每一頭牛的愿望就是變成一頭最受歡迎的牛。現在有N頭牛,給你M對整數(A,B),表示牛A認為牛B受歡迎。
? 這種關系是具有傳遞性的,如果A認為B受歡迎,B認為C受歡迎,那么牛A也認為牛C受歡迎。
? 你的任務是求出有多少頭牛被所有的牛認為是受歡迎的。
題解:
? 強連通縮點
? 唯一的一個出度為0的強連通分量
? 如果有多個出度為0的強連通分量則無解
代碼:
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; const int INF = 0x3f3f3f3f; struct node {int v, next; }edge[maxn]; vector<int>p; stack <int> s; int dfn[maxn],low[maxn]; int color[maxn],in[maxn]; int tot,block; int head[maxn],pre[maxn]; int n,m,cnt,C,X; bool vis[maxn]; void add(int from, int to) {edge[++cnt].v=to;edge[cnt].next=head[from];head[from]=cnt; } void tarjan(int u) {dfn[u]=low[u]= ++tot;vis[u]=1;s.push(u);for(int i=head[u];i!=-1;i=edge[i].next) {int v=edge[i].v;if (!dfn[v]) {tarjan(v);low[u]= min(low[u],low[v]);}else if(vis[v]) low[u]=min(low[u],dfn[v]);}if (dfn[u]==low[u]) {block++;int v;do {v=s.top();s.pop();color[v]=block;pre[block]=min(v, pre[block]);//pre保存的是同強連通分量中編號最小點 vis[v]=0;} while (v!=u);} }int main() {cin>>n>>m;memset(head,-1,sizeof(head));memset(pre,INF,sizeof(pre));for(int i=0;i<m;i++){int u,v;scanf("%d%d",&u,&v);add(u,v);}for(int i=1;i<=n;i++){if(!dfn[i]) tarjan(i);}for(int i=1;i<=n;i++){for(int j=head[i];j!=-1;j=edge[j].next){int u=color[i];int v=color[edge[j].v];if(u!=v)in[u]++; }}for(int i=1;i<=n;i++){//此處已經進行完壓縮,壓縮后還有block個點 if(!in[color[i]]) //如果一個點沒有入度 p.push_back(pre[i]);}//sort(p.begin(),p.end());//cout<<ans;cout<<p.size()<<endl;//for(int i=0;i<p.size();i++) cout<<p[i]<< " ";//cout<<endl;return 0; }總結
以上是生活随笔為你收集整理的第1节 连通性强连通、割点和桥 例题的全部內容,希望文章能夠幫你解決所遇到的問題。