题意:给出一张地图,一只牛可以从高度大的地方走到高处小的地方,高度相同的地方随便走,问最少连接几个块,可以使牛从任何一个点走到任何一个点。。
强连通,建图很简单,就是同样高度建个双相边,有高度差是单向边(高度大到高度小),然后tarjan缩点,然后统计缩点之后每个点的入度和出度,统计出度为0和入度为0的点,取这两个中的最大值。。。如果强连通分量只有一个,整张图都是连通的,输出0。。
然后就是RE了。。。。discuss里说交C++,交了C++。。居然TLE。。。然后就郁闷了。。。最后把vector换成邻接表就过了900+ms...
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int MAXN=510;
const int dir[4][2]={1,0,-1,0,0,1,0,-1};
int mp[MAXN][MAXN];
int n,m;
int sc_cnt,dfs_clock,sccno[MAXN*MAXN],pre[MAXN*MAXN],low[MAXN*MAXN];
stack<int> S;
struct EDGE
{
int v,next;
}edge[MAXN*MAXN*8];
int head[MAXN*MAXN],size;
void init()
{
memset(head,-1,sizeof(head));
memset(sccno,0,sizeof(sccno));
memset(pre,0,sizeof(pre));
sc_cnt=dfs_clock=size=0;
}
void add_edge(int u,int v)
{
edge[size].v=v;
edge[size].next=head[u];
head[u]=size++;
}
void tarjan(int u)
{
low[u]=pre[u]=++dfs_clock;
S.push(u);
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(!pre[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!sccno[v])
{
low[u]=min(low[u],pre[v]);
}
}
if(low[u]==pre[u])
{
sc_cnt++;
while(1)
{
int x=S.top();
S.pop();
sccno[x]=sc_cnt;
if(x==u)
break;
}
}
}
int in[MAXN*MAXN],out[MAXN*MAXN];
int solve()
{
int i,j,k;
int u,v;
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
for(k=0;k<4;k++)
{
int nx=i+dir[k][0];
int ny=j+dir[k][1];
if(nx<0||ny<0||nx>=n||ny>=m)
continue;
u=i*m+j;
v=nx*m+ny;
if(mp[i][j]>=mp[nx][ny])
{
add_edge(u,v);
}
if(mp[i][j]<=mp[nx][ny])
{
add_edge(v,u);
}
}
}
}
for(i=0;i<n*m;i++)
{
if(!pre[i])
tarjan(i);
}
if(sc_cnt==1)
{
return 0;
}
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(u=0;u<n*m;u++)
{
for(i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(sccno[u]!=sccno[v])
{
out[sccno[u]]++;
in[sccno[v]]++;
}
}
}
int a=0,b=0;
for(i=1;i<=sc_cnt;i++)
{
if(!in[i])
a++;
if(!out[i])
b++;
}
return max(a,b);
}
int main()
{
int i,j;
while(scanf("%d%d",&m,&n)==2)
{
init();
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
scanf("%d",&mp[i][j]);
}
}
printf("%d\n",solve());
}
}