題意:給出一張地圖,一隻牛可以從高度大的地方走到高處小的地方,高度相同的地方隨便走,問最少連接幾個塊,可以使牛從任何一個點走到任何一個點。。
強連通,建圖很簡單,就是同樣高度建個雙相邊,有高度差是單向邊(高度大到高度小),然後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());
}
}