题意:有一个 l * w 大小的滑雪场,每个格子都有一个高度,每个格子可以直接通到上下左右四个格子中高度小于等于自己的格子,现在要建立通道,能够连通任意两个格子,问最少建多少通道能够使所有格子能够互相到达。
其实就是问加多少条边能够使整个图强连通,也就是求强连通分量中入度为 0 和出度为 0 的分量个数的最大值,如果仅一个强连通分量则为 0 。
RE 10 发,我以为是因为我链式前向星数组开太大,于是换邻接矩阵,又 RE,一看DISCUSS,G++RE,C++AC,一交C++A了,把第一次RE的交了一发A了,所以RE的小伙伴们……交C++吧……
链式前向星:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h>
2 #include<string.h>
3 #include<stack>
4 #include<queue>
5 using namespace std;
6
7 const int maxn=250005;
8 const int maxm=1e6+5;
9
10 int head[maxn],point[maxm],nxt[maxm],size;
11 int n,t,scccnt;
12 int stx[maxn],low[maxn],scc[maxn];
13 int id[maxn],od[maxn];
14 int ma[505][505];
15 int xx[4]={1,-1,0,0};
16 int yy[4]={0,0,1,-1};
17 stack<int>S;
18
19 int max(int a,int b){return a>b?a:b;}
20
21 void init(){
22 memset(head,-1,sizeof(head));
23 size=0;
24 }
25
26 void add(int a,int b){
27 point[size]=b;
28 nxt[size]=head[a];
29 head[a]=size++;
30 }
31
32 void dfs(int s){
33 stx[s]=low[s]=++t;
34 S.push(s);
35 for(int i=head[s];~i;i=nxt[i]){
36 int j=point[i];
37 if(!stx[j]){
38 dfs(j);
39 low[s]=min(low[s],low[j]);
40 }
41 else if(!scc[j]){
42 low[s]=min(low[s],stx[j]);
43 }
44 }
45 if(low[s]==stx[s]){
46 scccnt++;
47 while(1){
48 int u=S.top();S.pop();
49 scc[u]=scccnt;
50 if(s==u)break;
51 }
52 }
53 }
54
55 void setscc(){
56 memset(stx,0,sizeof(stx));
57 memset(scc,0,sizeof(scc));
58 t=scccnt=0;
59 for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
60 for(int i=1;i<=n;++i){
61 for(int j=head[i];~j;j=nxt[j]){
62 int k=point[j];
63 if(scc[i]!=scc[k]){
64 od[scc[i]]++;
65 id[scc[k]]++;
66 }
67 }
68 }
69 }
70
71 int main(){
72 int w,l;
73 scanf("%d%d",&w,&l);
74 n=w*l;
75 init();
76 for(int i=1;i<=l;++i){
77 for(int j=1;j<=w;++j){
78 scanf("%d",&ma[i][j]);
79 }
80 }
81 for(int i=1;i<=l;++i){
82 for(int j=1;j<=w;++j){
83 for(int k=0;k<4;++k){
84 int x=i+xx[k],y=j+yy[k];
85 if(x>=1&&x<=l&&y>=1&&y<=w&&ma[x][y]<=ma[i][j]){
86 add((i-1)*w+j,(x-1)*w+y);
87 }
88 }
89 }
90 }
91 setscc();
92 if(scccnt==1)printf("0\n");
93 else{
94 int in=0,out=0;
95 for(int i=1;i<=scccnt;++i){
96 if(!id[i])in++;
97 if(!od[i])out++;
98 }
99 printf("%d\n",max(in,out));
100 }
101 }
邻接矩阵:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h>
2 #include<string.h>
3 #include<stack>
4 #include<queue>
5 using namespace std;
6
7 const int maxn=505*505;
8
9 int n,t,scccnt;
10 int w,l;
11 int stx[maxn],low[maxn],scc[maxn];
12 int id[maxn],od[maxn];
13 int ma[505][505];
14 int xx[4]={1,-1,0,0};
15 int yy[4]={0,0,1,-1};
16 stack<int>S;
17
18 int max(int a,int b){return a>b?a:b;}
19
20 inline int getid(int a,int b){
21 return (a-1)*w+b;
22 }
23
24 inline void getpoint(int num,int &a,int &b){
25 a=num/w;
26 b=num%w;
27 if(b)a++;
28 else b=w;
29 }
30
31 void dfs(int s){
32 stx[s]=low[s]=++t;
33 S.push(s);
34 int x,y;
35 getpoint(s,x,y);
36 for(int p=0;p<4;++p){
37 int dx=x+xx[p],dy=y+yy[p];
38 if(dx>=1&&dx<=l&&dy>=1&&dy<=w&&ma[dx][dy]<=ma[x][y]){
39 int j=getid(dx,dy);
40 if(!stx[j]){
41 dfs(j);
42 low[s]=min(low[s],low[j]);
43 }
44 else if(!scc[j]){
45 low[s]=min(low[s],stx[j]);
46 }
47 }
48 }
49 if(low[s]==stx[s]){
50 scccnt++;
51 while(1){
52 int u=S.top();S.pop();
53 scc[u]=scccnt;
54 if(s==u)break;
55 }
56 }
57 }
58
59 void setscc(){
60 memset(stx,0,sizeof(stx));
61 memset(scc,0,sizeof(scc));
62 t=scccnt=0;
63 for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
64 for(int i=1;i<=n;++i){
65 int x,y;
66 getpoint(i,x,y);
67 for(int p=0;p<4;++p){
68 int dx=x+xx[p],dy=y+yy[p];
69 if(dx>=1&&dx<=l&&dy>=1&&dy<=w&&ma[dx][dy]<=ma[x][y]){
70 int k=getid(dx,dy);
71 if(scc[i]!=scc[k]){
72 od[scc[i]]++;
73 id[scc[k]]++;
74 }
75 }
76 }
77 }
78 }
79
80 int main(){
81 scanf("%d%d",&w,&l);
82 n=w*l;
83 memset(id,0,sizeof(id));
84 memset(od,0,sizeof(od));
85 for(int i=1;i<=l;++i){
86 for(int j=1;j<=w;++j){
87 scanf("%d",&ma[i][j]);
88 }
89 }
90 setscc();
91 if(scccnt==1)printf("0\n");
92 else{
93 int in=0,out=0;
94 for(int i=1;i<=scccnt;++i){
95 if(!id[i])in++;
96 if(!od[i])out++;
97 }
98 printf("%d\n",max(in,out));
99 }
100 }