POJ - 2186 Popular Cows(强连通缩点)
生活随笔
收集整理的這篇文章主要介紹了
POJ - 2186 Popular Cows(强连通缩点)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接:點擊查看
題目大意:給出n只奶牛,以及m組可傳遞的關系,每組關系給出一個a和一個b,表示為a->b,意思是奶牛a覺得奶牛b很酷,因為關系可傳遞,所以如果a->b且b->c,能夠推出a->c,現在問有多少只奶牛,可以被其他所有的奶牛都認為很酷
題目分析:題目給出的是有向邊,且滿足條件的奶牛肯定可以被所有的點間接或直接到達,故是一個強聯通的題目,我們可以先用tarjan算法將整個有向圖縮點,每一個新的點所代表的集合中的點都可以兩兩互相到達,再根據原圖的邊建一個新圖,找到一個出度為0的點,那么答案就是出度為0的點所代表的集合中點的個數了,注意,若出度為0的點所代表的集合不唯一,那么肯定是無解的,直接輸出0就行了,相反,如果出度為0的點不存在,那么說明肯定形成了環,故所有的點都是滿足條件的,然后在縮點的時候記錄一下每個集合的大小就好了?
第二天更新:
第二天學習了有向圖的強聯通縮點,但實在不明白昨天我是怎么用無向圖的點雙縮點給亂搞出來的。。特地回去寫了一發應該算是正解代碼貼上吧,其實也是模板題,直接用tarjan強聯通縮點就行了
代碼:
無向圖點雙縮點:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e4+100;struct Egde {int to,next; }edge[N*10];int head[N],low[N],dfn[N],num,tot,c[N],dcc,out[N];bool bridge[N*10];vector<int>ans[N];void addedge(int u,int v) {edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++; }void tarjan(int u,int in_edge) {dfn[u]=low[u]=++num;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;if(!dfn[v]){tarjan(v,i);low[u]=min(low[u],low[v]);if(low[v]>dfn[u])bridge[i]=bridge[i^1]=true;}else if(i!=(in_edge^1))low[u]=min(low[u],dfn[v]);} }void dfs(int u) {c[u]=dcc;ans[dcc].push_back(u);for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;if(c[v]||bridge[i])continue;dfs(v);} }void init() {for(int i=0;i<N;i++)ans[i].clear();tot=num=dcc=0;memset(head,-1,sizeof(head));memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(bridge,false,sizeof(bridge));memset(c,0,sizeof(c));memset(out,0,sizeof(out)); }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);int n,m;while(scanf("%d%d",&n,&m)!=EOF){init();while(m--){int u,v;scanf("%d%d",&u,&v);addedge(u,v);addedge(v,u);}for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i,0);for(int i=1;i<=n;i++)if(!c[i]){dcc++;dfs(i);}for(int i=0;i<tot;i+=2){int u=edge[i^1].to;int v=edge[i].to;if(c[u]!=c[v])out[c[u]]++;}int cnt=0,mark;for(int i=1;i<=dcc;i++)if(out[i]==0){cnt++;mark=ans[i].size();}if(cnt==1)printf("%d\n",mark);else if(cnt==0)printf("%d\n",n);elseputs("0");}return 0; }有向圖強聯通縮點:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e4+100;const int M=5e4+100;struct Egde {int to,next; }edge1[M],edge2[M];int head1[N],head2[N],low[N],dfn[N],c[N],Stack[N],num,cnt,cnt2,cnt1,dcc,n,m,top,out[N];bool ins[N];vector<int>scc[N];void addedge1(int u,int v) {edge1[cnt1].to=v;edge1[cnt1].next=head1[u];head1[u]=cnt1++; }void addedge2(int u,int v) {edge2[cnt2].to=v;edge2[cnt2].next=head2[u];head2[u]=cnt2++; }void tarjan(int u) {dfn[u]=low[u]=++num;Stack[++top]=u;ins[u]=true;for(int i=head1[u];i!=-1;i=edge1[i].next){int v=edge1[i].to;if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}else if(ins[v])low[u]=min(low[u],dfn[v]);}if(dfn[u]==low[u]){cnt++;int v;do{v=Stack[top--];ins[v]=false;c[v]=cnt;scc[cnt].push_back(v);}while(u!=v);} }void solve() {for(int i=1;i<=n;i++)//縮點 if(!dfn[i])tarjan(i); }void build()//縮點+連邊 {solve();for(int i=1;i<=n;i++){for(int j=head1[i];j!=-1;j=edge1[j].next){int u=i;int v=edge1[j].to;if(c[u]!=c[v])addedge2(c[u],c[v]);}} }void init() {for(int i=0;i<N;i++)scc[i].clear();top=cnt=cnt1=cnt2=num=dcc=0;memset(head2,-1,sizeof(head2));memset(head1,-1,sizeof(head1));memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(c,0,sizeof(c));memset(ins,false,sizeof(ins));memset(out,0,sizeof(out)); }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);while(scanf("%d%d",&n,&m)!=EOF){init();while(m--){int u,v;scanf("%d%d",&u,&v);addedge1(u,v);}build();for(int i=1;i<=cnt;i++){for(int j=head2[i];j!=-1;j=edge2[j].next){int u=i;int v=edge2[j].to;if(u!=v)out[u]++;}}int tot=0,mark;for(int i=1;i<=cnt;i++)if(out[i]==0){tot++;mark=scc[i].size();}if(tot==1)printf("%d\n",mark);else if(tot==0)printf("%d\n",n);elseputs("0");}return 0; }?
總結
以上是生活随笔為你收集整理的POJ - 2186 Popular Cows(强连通缩点)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UVA - 11806 Cheerlea
- 下一篇: 无向图缩点:tarjan点双与边双缩点(