题意:给定一个滑雪场,每个点能向周围4个点高度小于等于这个点的点滑,现在要建电缆,使得任意两点都有路径互相可达,问最少需要几条电缆
思路:强连通缩点,每个点就是一个点,能走的建边,缩点后找入度出度为0的个数的最大值就是答案,注意一开始就强连通了答案应该是0
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N= 300000 ;
const int M= 2222222 ;
const int dx[] = {-1, 1, 0, 0};
const int dy[] = {0, 0, -1, 1};
struct node
{
int u , v , next ;
}edge[M] ;
int head[N],vist[N],low[N],dfn[N],belong[N],stack[N],g[505][505] ,out[N],in[N];
int top , sum , cnt , dep , n,m ;
int cheak(int i , int j)
{
if( i >= 0 && i < n && j >= 0 && j<m) return 1;
return 0;
}
void add(int u ,int v)
{
edge[top].u=u;
edge[top].v=v;
edge[top].next=head[u];
head[u]=top++;
}
void tarjan(int u )
{
low[u]=dfn[u]=++dep;
stack[cnt++]=u;
vist[u]=1;
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(vist[v])
low[u] = min( low[u] , dfn[v] );
}
if(low[u] == dfn[u])
{
int x;
sum++ ;
do
{
x=stack[--cnt] ;
vist[x] = 0 ;
belong[x]=sum;
}while(x!=u) ;
}
}
int main()
{ int w =0;
while(~scanf("%d%d",&m,&n))
{
top =0 ; sum = 0 ;dep = 0 ;cnt = 0 ;
memset(head,-1,sizeof(head)) ;
memset(low,0,sizeof(low)) ;
memset(dfn,0,sizeof(dfn)) ;
memset(vist,0,sizeof(vist)) ;
memset(out,0,sizeof(out));
memset(in,0,sizeof(in));
for(int i = 0 ; i < n ; i++)
for(int j = 0 ; j < m ; j++)
scanf("%d",&g[i][j]) ;
for(int i = 0 ; i < n ; i++)
for(int j = 0 ; j < m ; j++)
for(int k = 0 ; k < 4 ; k++)
{
int xx = i + dx[k] ;
int yy = j + dy[k] ;
int u = i*m+j ,v=xx*m+yy ;
if(cheak(xx,yy))
{
if(g[i][j] >= g[xx][yy])
{
add(u,v);w++;
}
if(g[i][j] <= g[xx][yy])
{
add(v,u);w++;
}
}
}
// printf("%d\n",w);
for(int i = 0 ; i < n*m ; i++)
if(!dfn[i])
tarjan(i) ;
// printf("*%d* ",sum);
for(int i = 0 ; i < n*m ; i++)
for(int j= head[i] ; j!=-1; j=edge[j].next)
{
int v = edge[j].v ;
if(belong[i] != belong[v])
{
in[belong[v]]++ ;
out[belong[i]]++;
}
}
if(sum <= 1 ) //刚开始强联通的
printf("0\n") ;
else
{
int a=0,b=0;
for(int i = 1 ; i <= sum ; i++)
{
if(out[i] == 0)
a++ ;
if(in[i] == 0)
b++ ;
}
printf("%d\n",max(a,b)) ;
}
}
return 0;
}