蓝书3.5 强连通分量

T1 受欢迎的牛  bzoj 1051

题解链接

T2 最大半连通子图 bzoj 1093

题目大意:

一个半连通的图定义为对任意点对u v 存在路径u->v或v->u

求给定图的最大半连通子图

思路:

可以知道 半连通子图一定为强连通分量缩点之后的链

所以只需要求一个最长链然后记一下方案数 需要注意第二次建图之后会有很多重边

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 2139062143
10 #define ll long long
11 #define MAXN 100100
12 #define eps 1e-9
13 using namespace std;
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 int n,m,mod,to[MAXN*10],nxt[MAXN*10],fst[MAXN],cnt;
22 int To[MAXN*10],Nxt[MAXN*10],Fst[MAXN],dp[MAXN],ans,res,num[MAXN];
23 int st[MAXN],top,dfn[MAXN],low[MAXN],scc,stp,vis[MAXN],sz[MAXN],bl[MAXN];
24 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
25 void Add(int u,int v) {Nxt[++cnt]=Fst[u],Fst[u]=cnt,To[cnt]=v;}
26 void tarjan(int x)
27 {
28     dfn[x]=low[x]=++stp,st[++top]=x,vis[x]=1;
29     for(int i=fst[x];i;i=nxt[i])
30         if(!dfn[to[i]]) {tarjan(to[i]);low[x]=min(low[x],low[to[i]]);}
31         else if(!bl[to[i]]) low[x]=min(low[x],dfn[to[i]]);
32     if(low[x]==dfn[x])
33     {
34         scc++;int now=0;
35         while(now!=x)
36             now=st[top--],vis[now]=0,bl[now]=scc,sz[scc]++;
37     }
38 }
39 void build()
40 {
41     for(int x=1;x<=n;x++)
42         for(int i=fst[x];i;i=nxt[i])
43             if(bl[to[i]]!=bl[x]) Add(bl[x],bl[to[i]]);
44 }
45 void dfs(int x)
46 {
47     vis[x]=num[x]=1;
48     bool v[MAXN]={0};
49     for(int i=Fst[x];i;i=Nxt[i])
50     {
51         if(v[To[i]]) continue;
52         v[To[i]]=1;
53         if(!vis[To[i]]) dfs(To[i]);
54         if(dp[x]==dp[To[i]]) (num[x]+=num[To[i]])%=mod;
55         else if(dp[To[i]]>dp[x]) num[x]=num[To[i]],dp[x]=dp[To[i]];
56     }
57     dp[x]+=sz[x],res=max(res,dp[x]);
58 }
59 int main()
60 {
61     n=read(),m=read(),mod=read();int a,b;
62     while(m--) {a=read(),b=read();add(a,b);}
63     for(int i=1;i<=n;i++)
64         if(!dfn[i]) tarjan(i);
65     cnt=0;build();
66     for(int i=1;i<=scc;i++)
67         if(!vis[i]) dfs(i);
68     for(int i=1;i<=scc;i++) if(dp[i]==res) (ans+=num[i])%=mod;
69     printf("%d
%d",res,ans);
70 }
View Code

T3 Network of Schools poj 1236

题目大意:

有向图 在图上的点染色 颜色会沿边运动 

求最少给多少个点染色会使整个图都被染色以及最少再加多少边使给任意一点染色都可以使整张图被染色

思路:

第一问很明显是缩点后入度为0的点个数

第二问应该讲每条链的首尾相接 因此答案为缩点后max(入度为0,出度为0)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 2139062143
10 #define ll long long
11 #define MAXN 10100
12 #define eps 1e-9
13 using namespace std;
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 int n,m,mod,to[MAXN<<1],nxt[MAXN<<1],fst[MAXN],cnt;
22 int To[MAXN<<1],Nxt[MAXN<<1],Fst[MAXN],ans,res,Ind[MAXN],Od[MAXN];
23 int st[MAXN],top,dfn[MAXN],low[MAXN],scc,stp,vis[MAXN],sz[MAXN],bl[MAXN];
24 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
25 void Add(int u,int v) {Nxt[++cnt]=Fst[u],Fst[u]=cnt,To[cnt]=v,Ind[v]++,Od[u]++;}
26 void tarjan(int x)
27 {
28     dfn[x]=low[x]=++stp,st[++top]=x,vis[x]=1;
29     for(int i=fst[x];i;i=nxt[i])
30         if(!dfn[to[i]]) {tarjan(to[i]);low[x]=min(low[x],low[to[i]]);}
31         else if(!bl[to[i]]) low[x]=min(low[x],dfn[to[i]]);
32     if(low[x]==dfn[x])
33     {
34         scc++;int now=0;
35         while(now!=x)
36             now=st[top--],vis[now]=0,bl[now]=scc,sz[scc]++;
37     }
38 }
39 void build()
40 {
41     for(int x=1;x<=n;x++)
42         for(int i=fst[x];i;i=nxt[i])
43             if(bl[to[i]]!=bl[x]) Add(bl[x],bl[to[i]]);
44 }
45 int main()
46 {
47     n=read();int a;
48     for(int i=1;i<=n;i++) while(1) {a=read();if(!a) break;add(i,a);}
49     for(int i=1;i<=n;i++)
50         if(!dfn[i]) tarjan(i);
51     cnt=0;build();
52     for(int i=1;i<=scc;i++) if(!Ind[i]) ans++;
53     for(int i=1;i<=scc;i++) if(!Od[i]) res++;
54     if(scc==1) printf("1
0");
55     else printf("%d
%d",ans,max(res,ans));
56 }
View Code

T4 间谍网络 luogu 1262

题目大意:

有向图 有些点可以染色 颜色会沿边运动 这些点染色花费不同 

求是否能将整张图染色 以及最小费用

思路:

缩点之后求出每个点是否能被染色以及最小费用 

判断所有入度为0的点是否能被染色 将他们的费用加起来

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 2139062143
10 #define ll long long
11 #define MAXN 10100
12 #define eps 1e-9
13 using namespace std;
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 int n,m,to[MAXN],nxt[MAXN],fst[MAXN],cnt,val[MAXN],ok[MAXN];
22 int To[MAXN],Nxt[MAXN],Fst[MAXN],ans,res,cst[MAXN],Ind[MAXN],rep[MAXN];
23 int st[MAXN],top,dfn[MAXN],low[MAXN],scc,stp,vis[MAXN],Ok[MAXN],bl[MAXN];
24 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
25 void Add(int u,int v) {Nxt[++cnt]=Fst[u],Fst[u]=cnt,To[cnt]=v,Ind[v]++;}
26 void tarjan(int x)
27 {
28     dfn[x]=low[x]=++stp,st[++top]=x,vis[x]=1;
29     for(int i=fst[x];i;i=nxt[i])
30         if(!dfn[to[i]]) {tarjan(to[i]);low[x]=min(low[x],low[to[i]]);}
31         else if(!bl[to[i]]) low[x]=min(low[x],dfn[to[i]]);
32     if(low[x]==dfn[x])
33     {
34         scc++;int now=0;
35         while(now!=x)
36             now=st[top--],vis[now]=0,bl[now]=scc,Ok[scc]|=ok[now],cst[scc]=min(cst[scc],val[now]),rep[scc]=now;
37     }
38 }
39 void build()
40 {
41     for(int x=1;x<=n;x++)
42         for(int i=fst[x];i;i=nxt[i])
43             if(bl[to[i]]!=bl[x]) Add(bl[x],bl[to[i]]);
44 }
45 int main()
46 {
47     memset(val,127,sizeof(val));memset(cst,127,sizeof(cst));
48     n=read(),m=read();int a,b;
49     while(m--) a=read(),ok[a]=1,val[a]=read();m=read();
50     while(m--) {a=read(),b=read();add(a,b);}
51     for(int i=1;i<=n;i++)
52         if(!dfn[i]) tarjan(i);
53     cnt=0;build();
54     for(int i=1;i<=scc;i++) if(!Ind[i])
55         if(!Ok[i]) {printf("NO
%d",rep[i]);return 0;}
56         else ans+=cst[i];
57     printf("YES
%d",ans);
58 }
View Code

T5 Atm bzoj 1179

题解链接

原文地址:https://www.cnblogs.com/yyc-jack-0920/p/9372747.html