图论——LCA、强联通分量、桥、割顶、二分图最大匹配、网络流

A: 交通运输线

时间限制: 5 Sec  内存限制: 128 MB

题目描述

战后有很多城市被严重破坏,我们需要重建城市。然而,有些建设材料只能在某些地方产生。因此,我们必须通过城市交通,来运送这些材料的城市。由于大部分道路已经在战争期间完全遭到破坏,可能有两个城市之间没有道路。当然在运输线中,更不可能存在圈。 
现在,你的任务来了。给你战后的道路情况,我们想知道,两个城市之间是否存在道路,如果存在,输出这两个城市之间的最短路径长度。

输入

第一行一个整数Case(Case<=10)表示测试数据组数。 
每组测试数据第一行三个整数N,M和C (2<=N<=10, 000) (0<=M<10, 000) (1<=c<=1000000)共有N个城市,现存M条边,共有C对运输需求。 
接下来M行,每行三个整数A和B,D(1<=A,B<=N,A不等于B)表示从A到B有一条直接的公路,且距离为D。 
最后C行,每行两个整数,S和T(1<=S,T<=N,S不等于T),即询问从S到T的最短路径长度。

输出

共Case行,否存在从S到T的路径,则输出最短路径,否则输出“Not connected”。

样例输入

1

5 3 2

1 3 2

2 4 3

5 2 3

1 4

4 5

样例输出

Not connected

6

这题总不能直接跑个最短路吧,

肯定有什么条件没用到,给你的图还是个森林。

显然的,两个点在不同树上就不联通,那在同一个树上的最短路呢?

画几个图你会发现两个点间只有一条简单路径,不就是最短路了吗?

证明的话,用反证法如果存在另一条简单路径,图就不是树了。

好了,先在我们就可以用LCA求出这个最短路径。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;
 7 #define N 2000005
 8 queue<int> Q;
 9 int dis[N],v[N],col[N],fa[N],anc[N],ans[N];
10 struct node{
11     int v,c;
12 };
13 vector<node> vec[N];
14 vector<node> vec_[N];
15 int find(int x){
16     return x==fa[x]?x:fa[x]=find(fa[x]);
17 }
18 void Dis(int u,int f){
19     v[u]=1;
20     for (int size=vec[u].size(),i=0;i<size;i++)
21     if (vec[u][i].v!=f){
22         dis[vec[u][i].v]=dis[u]+vec[u][i].c;
23         Dis(vec[u][i].v,u);
24     }
25 }
26 void LCA(int u,int f){
27     Q.push(u); v[u]=1; fa[u]=u; anc[u]=u;
28     for (int size=vec[u].size(),i=0;i<size;i++)
29     if (vec[u][i].v!=f){
30         int v_=vec[u][i].v;
31         LCA(v_,u);
32         int f_a=find(v_),f_b=find(u);
33         fa[f_a]=f_b;
34         anc[f_b]=u;
35     }
36     col[u]=1;
37     for (int size=vec_[u].size(),i=0;i<size;i++)
38         if (col[vec_[u][i].v]){
39             ans[vec_[u][i].c]=dis[u]+dis[vec_[u][i].v]-dis[anc[find(vec_[u][i].v)]]-dis[anc[find(vec_[u][i].v)]];
40     }
41 }
42 int main(){
43     int Case; scanf("%d",&Case);
44     while (Case--){
45         int n,m,c; scanf("%d%d%d",&n,&m,&c);
46         for (int i=1;i<=n;i++) {
47             vec[i].clear();
48             dis[i]=0;
49         }
50         for (int i=1;i<=c;i++) ans[i]=-1,vec_[i].clear();
51         for (int i=1;i<=m;i++){
52             int a,b,c; scanf("%d%d%d",&a,&b,&c);
53             vec[a].push_back({b,c});
54             vec[b].push_back({a,c});
55         }
56         for (int i=1;i<=c;i++){
57             int a,b; scanf("%d%d",&a,&b);
58             vec_[a].push_back({b,i});
59             vec_[b].push_back({a,i});
60         }
61         for (int i=1;i<=n;i++) v[i]=0;
62         for (int i=1;i<=n;i++)
63           if (!v[i]){
64             Dis(i,0);
65           }
66         for (int i=1;i<=n;i++) v[i]=0;
67         for (int i=1;i<=n;i++)
68           if (!v[i]) {
69             while (!Q.empty()) col[Q.front()]=0,Q.pop();
70             LCA(i,0);
71           }
72         for (int i=1;i<=c;i++)
73             if (ans[i]==-1) printf("Not connected\n");
74             else printf("%d\n",ans[i]);
75     }
76     return 0;
77 }

B:这不是Floyd

时间限制: 1 Sec  内存限制: 128 MB

题目描述

当一个有向图给出,我们可以通过著名的Floyd算法方便的求解出其传递闭包。 
但如果你给一个图G=(V,E),您能不能给一个的最小的边集合代替原边集,使得新的图与原图各个顶点的传递性不变。

输入

有多组测试数据: 
第一行,包含一个整数Num,表示测试数据的个数。(1<=Num<=100) 
每组测试数据,第一行一个整数N(1<=N<=200)。 
接下来N行N列的一个0,1矩阵,表示相应点对之间的连接关系。第i行第j列,若值为1,则表示有一条从i到j的有向边。否则就没有。

输出

每行输出一个整数。输出至少需要多少条边,就能与原图的传递性一致。

样例输入

4

1

1

2

1 0

0 1

2

1 1

1 1

3

1 1 1

0 1 1

0 0 1

样例输出

0

0

2

2

简单的想法,一个强连通图里里只要个数条边(一个点不算),

然后我们可以尝试去缩点得到一个DAG,

然后就是玄学了,如果一条边去掉后对图的联通性没有影响就可以去掉。

感觉能用拓扑图证一下。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
31 ll read(){ ll ans=0; char last=‘ ‘,ch=getchar();
32 while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar();
33 while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar();
34 if(last==‘-‘)ans=-ans; return ans;
35 }
36 #define N 80005
37 #define mem(a) memset(a,0,sizeof(a))
38 int v[N],next[N],head[N],Stack[N],Ins[N],dfn[N],low[N],belong[N],map[205][205],map_[205][205],E,e,Time,top,sum[N],ans,len,l[N],r[N];
39 void add(int x,int y){ v[++e]=y; next[e]=head[x]; head[x]=e; }
40 void dfs(int u){
41     dfn[u]=low[u]=++Time; Stack[++top]=u; Ins[u]=1;
42     for (int i=head[u];i;i=next[i])
43     if (dfn[v[i]]==0){
44         dfs(v[i]);
45         low[u]=min(low[u],low[v[i]]);
46     } else if (Ins[v[i]]) low[u]=min(low[u],dfn[v[i]]);
47     if (dfn[u]==low[u]){
48         E++;
49         while (Stack[top]!=u){
50             belong[Stack[top]]=E; sum[E]++;
51             Ins[Stack[top]]=0; top--;
52         }
53         belong[Stack[top]]=E; sum[E]++;
54         Ins[Stack[top]]=0; top--;
55         if (sum[E]>1) ans+=sum[E];
56     }
57 }
58 int main()
59 {
60     int T=read();
61     while (T--){
62         int n=read(); ans=E=e=Time=top=len=0;
63         mem(v),mem(next),mem(head),mem(Stack),mem(Ins);
64         mem(dfn),mem(low),mem(belong),mem(map),mem(map_),mem(sum),mem(l),mem(r);
65         for (int i=1;i<=n;i++)
66             for (int j=1;j<=n;j++){
67                 map[i][j]=read();
68                 if (map[i][j]) add(i,j);
69         }
70         for (int i=1;i<=n;i++)
71             if (dfn[i]==0) dfs(i);
72         for (int i=1;i<=n;i++)
73             for (int j=1;j<=n;j++)
74                 if (map[i][j] && belong[i]!=belong[j]){
75                     len++; l[len]=belong[i]; r[len]=belong[j]; map_[belong[i]][belong[j]]++;
76                 }
77         ans+=len;
78         for(int k=1;k<=E;k++)
79             for(int i=1;i<=E;i++)
80                 for(int j=1;j<=E;j++)
81                     map_[i][j]=map_[i][j]+map_[i][k]*map_[k][j];
82         for(int i=1;i<=len;i++)
83         {
84             map_[l[i]][r[i]]--;
85             if(map_[l[i]][r[i]]==0) map_[l[i]][r[i]]++;
86             else ans--;
87         }
88         printf("%d\n",ans);
89     }
90     return 0;
91  } 

C: 图中的项链

时间限制: 1 Sec  内存限制: 128 MB

题目描述

一个无向图中的项链,是由一系列圈组成,C1,C2,……,Ck(K>=1),并且符合如下规定: 
1. 任何两个圈都没有公共边; 
2. 任意两个相邻的圈有且仅有一个公共点; 
3. 任意两个不相邻的圈没有公共点。 
4. 任意一个点,至多只能出现在一个圈中一次。 
现在要求一个从S到T的项链,C1,C2,……,Ck(K>=1),其中S属于C1,T属于Ck。 
给定一个无向图,以及两个点S和T,问是否存在从S到T的项链。

输入

第一行一个整数Case(Case<=10)表示测试数据组数。 
每组测试数据第一行两个整数N,M N (2<=N<=10, 000) (1<=M<=100, 000)分别表示无向图中点的数目和边的数目。 
接下来M行,每行两个整数A和B(1<=A B<=N,A不等于B)表示有一条无向边从A到B。 
最后两个整数S和T(1<=S T<=N,S不等于T)

输出

共Case行,输出”YES”或”No”,表示是否存在从S到T的项链。

样例输入

3

3 3

1 2

2 3

3 1

1 3

4 5

1 2

2 3

1 3

3 4

3 4

1 4

4 5

1 2

1 2

2 3

3 4

3 4

1 4

样例输出

YES

YES

NO

这种题给的条件太多了,肯定有没用的,或可以放宽的。

3,4完全是屁话。不用鸟它,2可以合并到1上。

1不就是双联通分量吗?

WOC模板题。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 //void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
31 ll read(){ ll ans=0; char last=‘ ‘,ch=getchar();
32 while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar();
33 while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar();
34 if(last==‘-‘)ans=-ans; return ans;
35 }
36 #define N 200005
37 #define mem(a) memset(a,0,sizeof(a))
38 int s,t,v[N],next[N],head[N],E[N],vis[N],e,e_,dfn[N],low[N],Time,Stack[N],top,p[N];
39 void add(int x,int y,int e_){ v[++e]=y; next[e]=head[x]; head[x]=e; E[e]=e_;}
40 void dfs(int u){
41     vis[u]=1; dfn[u]=low[u]=++Time; Stack[++top]=u;
42     for (int i=head[u];i;i=next[i])
43     if(!vis[v[i]])
44     {
45         p[v[i]]=E[i];
46         dfs(v[i]);
47         low[u]=min(low[u],low[v[i]]);
48     }
49     else if(p[u]!=E[i])
50         low[u]=min(low[u],dfn[v[i]]);
51     if (low[u]==dfn[u]){
52          if (u==s){
53                 for (int i=1;i<=top;i++)
54                     if (Stack[i]==t) {
55                             cout<<"YES"<<endl;
56                             return;
57                         }
58                 cout<<"NO"<<endl; return;
59             } else {
60                 while (top>=1 && Stack[top]!=u) top--;
61                 top--;
62             }
63        }
64 }
65 int main()
66 {
67     int T=read();
68     while (T--){
69         int n=read(),m=read();
70         mem(head),mem(vis),mem(v),mem(low),mem(dfn),mem(next),mem(E),mem(Stack),mem(p);
71         e=e_=Time=top=0;
72         for (int i=1;i<=m;i++){
73             int a=read(),b=read();
74             add(a,b,++e_); add(b,a,e_);
75         }
76         s=read(),t=read();
77         dfs(s);
78     }
79     return 0;
80  } 

D: 桐桐的糖果计划

时间限制: 1 Sec  内存限制: 128 MB

题目描述

桐桐很喜欢吃棒棒糖。他家处在一大堆糖果店的附近。 但是,他们家的区域经常出现塞车、塞人等情况,这导致他不得不等到塞的车或人走光了他才能去买到他最爱吃的棒棒糖品种。于是,他去找市长帮他修路,使得每两个糖果店之间至少有两条完全不同的路。可是市长经费有限,于是让桐桐找出哪些路被塞住后会使某些糖果店与糖果店间无法到达及最少的修路条数。你能帮助他吃到他最喜爱的糖果吗? 注:1-> 3-> 2    和  1-> 3-> 4-> 2  为不完全不同的路,即不符合题意的路。         1-> 3-> 4-> 2  和  1-> 5-> 2  为完全不同的路,即符合题意的路。

输入

输入第一行是两个数n,m(n< =5000,m< =10000) 接下来的m行,每行两个数i,j,表示i,j间有一条边连接。

输出

输出有两行。第一行为塞住后就不可以到达某些糖果店的道路条数,第二行为最少的修路条数。

样例输入

7 7

1 2

2 3

3 4

2 5

4 5

5 6

5 7

样例输出

3

2

又一道模板题飘过,求桥,和缩点后树上入度为1的(个数+1)/2。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
31 ll read(){ ll ans=0; char last=‘ ‘,ch=getchar();
32 while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar();
33 while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar();
34 if(last==‘-‘)ans=-ans; return ans;
35 }
36 #define N 20005
37 int v[N],next[N],head[N],E[N],cut[N],dfn[N],low[N],Stack[N],belong[N],Ins[N],top,e,e_,Time,p[N],num,nu[N],ans,ans_;
38 void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; E[e]=z; }
39 void dfs(int u){
40     dfn[u]=low[u]=++Time; Stack[++top]=u; Ins[u]=1;
41     for (int i=head[u];i;i=next[i])
42     if (dfn[v[i]]==0){
43         p[v[i]]=E[i];
44         dfs(v[i]);
45         low[u]=min(low[u],low[v[i]]);
46         if (low[v[i]]>dfn[u])
47             cut[i]=1,ans_++;
48     } else if (E[i]!=p[u]) low[u]=min(low[u],dfn[v[i]]);
49     if (low[u]==dfn[u]){
50         num++;
51         while (Stack[top]!=u) {
52             Ins[Stack[top]]=0;
53             belong[Stack[top]]=num;
54             top--;
55         }
56         Ins[Stack[top]]=0;
57         belong[Stack[top]]=num;
58         top--;
59     }
60 }
61 int main()
62 {
63     int n=read(),m=read();
64     for (int i=1;i<=m;i++){
65         int a=read(),b=read();
66         add(a,b,++e_); add(b,a,e_);
67     }
68     for (int i=1;i<=n;i++)
69         if (dfn[i]==0) dfs(i);
70     for (int i=1;i<=n;i++){
71         for (int j=head[i];j;j=next[j])
72         if (cut[j]){
73             nu[belong[i]]++; nu[belong[v[j]]]++;
74         }
75     }
76     for (int i=1;i<=num;i++)
77         if (nu[i]==1) ans++;
78     printf("%d\n",ans_);
79     printf("%d",(ans+1)/2);
80     return 0;
81  } 

E: [USACO 4.2.2]完美的牛栏

时间限制: 1 Sec  内存限制: 64 MB

题目描述

农夫约翰上个星期刚刚建好了他的新牛棚,他使用了最新的挤奶技术。不幸的是,由于工程问题,每个牛栏都不一样。第一个星期,农夫约翰随便地让奶牛们进入牛栏,但是问题很快地显露出来:每头奶牛都只愿意在她们喜欢的那些牛栏中产奶。上个星期,农夫约翰刚刚收集到了奶牛们的爱好的信息(每头奶牛喜欢在哪些牛栏产奶)。一个牛栏只能容纳一头奶牛,当然,一头奶牛只能在一个牛栏中产奶。 给出奶牛们的爱好的信息,计算最大分配方案。

输入

第一行 两个整数,N (0 <= N <= 200) 和 M (0 <= M <= 200) 。N 是农夫约翰的奶牛数量,M 是新牛棚的牛栏数量。 第二行到第N+1行 一共 N 行,每行对应一只奶牛。第一个数字 (Si) 是这头奶牛愿意在其中产奶的牛栏的数目 (0 <= Si <= M) 。后面的 Si 个数表示这些牛栏的编号。牛栏的编号限定在区间 (1..M) 中,在同一行,一个牛栏不会被列出两次。

输出

只有一行。输出一个整数,表示最多能分配到的牛栏的数量。

样例输入

5 5

2 2 5

3 2 3 4

2 1 5

3 1 2 5

1 2

样例输出

4

二分图最大匹配

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=‘ ‘,ch=getchar();
33 while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar();
34 while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar();
35 if(last==‘-‘)ans=-ans; return ans;
36 }
37 int n,m,map[300][300],v[300],match[300],ans;
38 bool dfs(int x){
39     int t;
40     for (int i=1;i<=m;i++)
41     if (!v[i] && map[x][i]){
42         v[i]=1;
43         t=match[i];
44         match[i]=x;
45         if (t==-1||dfs(t))
46             return 1;
47         match[i]=t;
48     }
49     return 0;
50 }
51 int main()
52 {
53     n=read(),m=read();
54     memset(match,255,sizeof(match));
55     for (int i=1;i<=n;i++){
56         int t=read();
57         for (int j=1;j<=t;j++) {
58             int a=read();
59             map[i][a]=1;
60         }
61     }
62     for (int i=1;i<=n;i++){
63         memset(v,0,sizeof(v));
64         if (dfs(i)) ans++;
65     }
66     cout<<ans<<endl;
67     return 0;
68  } 

时间: 2024-10-14 15:06:19

图论——LCA、强联通分量、桥、割顶、二分图最大匹配、网络流的相关文章

POJ 2186-Popular Cows (图论-强联通分量Korasaju算法)

题目链接:http://poj.org/problem?id=2186 题目大意:有n头牛和m对关系, 每一对关系有两个数(a, b)代表a牛认为b牛是“受欢迎”的,且这种关系具有传递性, 如果a牛认为b牛“受欢迎”, b牛认为c牛“受欢迎”, 那么a牛也认为c牛“受欢迎”. 现在想知道有多少头牛受除他本身外其他所有牛的欢迎? 解题思路:如果有两头或者多头牛受除他本身外其他所有牛的欢迎, 那么在这两头或者多头牛之中, 任意一头牛也受两头或者多头牛中别的牛的欢迎, 即这两头或者多头牛同属于一个强联

【最小割】【Dinic】【强联通分量缩点】bzoj1797 [Ahoi2009]Mincut 最小割

结论: 满足条件一:当一条边的起点和终点不在 残量网络的 一个强联通分量中.且满流. 满足条件二:当一条边的起点和终点分别在 S 和 T 的强联通分量中.且满流.. 网上题解很多的. 1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 #define IN

【小结】强联通分量分解

强联通分量 在一个有向图的顶点子集S中,对?(u,v),如果都能找到一条从u到v的路径,那么就称S是强联通的.如果向S中加入任何一个其他顶点后S都不再是强联通的,就称S时原图的一个强联通分量. 显然,如果把所有的强联通分量都缩点,原图将变成一个DAG SCC的求解可通过两次dfs实现,第一次在原图中后续遍历,标号:第二遍将所有边反向后,从编号最大的点开始遍历,每次都可得到一个SCC. #include <cstdio> #include <cstring> #include <

爆零后的感受外加一道强联通分量HDU 4635的题解

今天又爆零了,又是又,怎么又是又,爆零爆多了,又也就经常挂嘴边了,看到这句话,你一定很想说一句"",弱菜被骂傻,也很正常啦. 如果你不开心,可以考虑往下看. 翻到E(HDU 4635 Strongly connected)题,这么短的题目,肯定要先看啦.然后D(LightOJ 1229),然后C(ZOJ 2243),然后F(HDU 4711),然后B(CodeForces 385D),然后看A(HDU 3889)好吧,我承认,A题看了一眼就不看了,B题一看是线段什么有点几何的味道就果断

【POJ1236】Network of Schools 强联通分量缩点(本文kosaraju)

/*不要说这题多水之类的--我只是想记一下kosaraju这种屌炸天的dfs序延伸算法(说不定能加到我的ygylca里面)*/ 题意神马的都不说了,好吧,就是给你个图,n个点,然后n行每行都描述该点的出边,图建完了,然后缩点,然后问多少个点没有入度,再问需要加几条边可以让图变强联通图. 强联通图:图中任意两点之间都能互相到达(前提得是有向图你懂的,无向图就有点乱了,根本不要算法了,暴搜就好了) 强联通分量:同强联通图,不过是图中一部分. 缩点,把一个分量视为一个点,缩起来(一般不缩,都是记录每个

强联通分量再探 By cellur925

我真的好喜欢图论啊. (虽然可能理解的并不深hhh) 上一次(暑假)我们初探了强联通分量,这一次我们再探.(特别感谢pku-lyc老师的课件.有很多引用) 上次我们忘记讨论复杂度了.tarjan老爷爷的算法都很strong as flash.这次是O(N). 强联通分量中任何两个点可互相到达.(显然的性质,但是需要强调识别.) 上一次例题遗漏的性质 有向无环图中唯一出度为 0 的点,一定可以由任何点出发均可达 来丢几道例题跑. 例题1 Network ? N个学校之间有单向的网络(是有向连通图)

POJ 2186 Popular cows(Kosaraju+强联通分量模板)

题目链接:http://poj.org/problem?id=2186 题目大意:给定N头牛和M个有序对(A,B),(A,B)表示A牛认为B牛是红人,该关系具有传递性,如果牛A认为牛B是红人,牛B认为牛C是红人,那么牛A也认为牛C是红人.求被其他所有牛认为是红牛的牛的总数. 解题思路:把所有牛看成顶点,把有序对(A,B)看成从A到B的有向边,那么题目就变成了求所有顶点都可到达的顶点的总数.我们可以得到一个结论,如果一个强连通分量里有一头牛被认为是红人,那么该强联通分量里的所有牛都是红人,这显然是

Light OJ 1034 - Hit the Light Switches(强联通分量)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1034 题目大意:有n盏灯,有m个关系, 关系a,b表示如果a灯开关打开那么b灯也会亮起来, 现在求至少需要打开多少开关使所有灯都亮. 题目思路:先由强联通分量缩点, 得到DAG图, 然后根据DAG图,求出有多少入度为0的点, 即为所求. 代码如下: #include<bits/stdc++.h> using namespace std; const int N = 1000

[BZOJ1051] [HAOI2006] 受欢迎的牛 (强联通分量)

Description 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这 种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎.你的任务是求出有多少头 牛被所有的牛认为是受欢迎的. Input 第一行两个数N,M. 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可 能出现多个A,B) Output 一个数,即有多少头牛被所有的牛认为是受欢迎的. Sample Input 3

[CF #236 (Div. 2) E] Strictly Positive Matrix(强联通分量)

题目:http://codeforces.com/contest/402/problem/E 题意:给你一个矩阵a,判断是否存在k,使得a^k这个矩阵全部元素都大于0 分析:把矩阵当作01矩阵,超过1的都当作1,那么a矩阵可表示一个有向图的走一次的连通性,则a^k表示有向图走K次的连通性.既然要求最后都没0,即走了K次后,每个点都能互通,这也说明这个图必然是只有一个强联通分量.于是判断k的存在有无,也就是判断a矩阵表示的有向图是不是只有一个强联通分量.