poj 2375 Cow Ski Area
http://poj.org/problem?id=2375
题目大意:FR为自己的牛建立了一个H*W的矩形溜冰场,每一个小方格都有一个高度L,牛只能向相邻的小方格滑动(即上下左右),而且相邻的小方格的高度不能比当前高度高。为了使牛能够从任意一点到达任意其他的点。FR打算买一些ski lifts。它能够连接两个小方格,使得这两个小方格能够相互到达(与高度无关)。问至少需要多少ski lifts。使得牛能够从任意一点到达任意其他的点。
解题思路:将此矩阵看成一个图。如果一个小方格能过到达相邻的一个小方格。那么它们之间就相当于有一条边。然后对此图求强连通分量。ans = Max(入度为0的连通分量数目,出度为0的连通分量数目)。还需要注意的就是如果此图本身就是一个强连通分量,那么答案就是0了,而不是1.(不然会WA)。
ps:如果用g++交的话,tarjan要写成非递归的,不然RE。

#include<set> #include<map> #include<stack> #include<queue> #include<cmath> #include<bitset> #include<string> #include<climits> #include<cstdio> #include<vector> #include<utility> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define IN puts("in") #define OUT puts("out") #define FR(x) freopen(x,"r",stdin) #define FW(x) freopen(x,"w",stdout) #define MSET(x,y) memset(x,y,sizeof(x)) #define ST system("pause") using namespace std; const int maxn = 260000; struct nd { int u,v,next; }edge[maxn*4]; int head[maxn],dfn[maxn],low[maxn],vis[maxn],st[maxn],zha[maxn],cur[maxn],belong[maxn],in[maxn],out[maxn],as[505][505]; int dx[] = {1,-1,0,0}; int dy[] = {0,0,1,-1}; int ecnt,cnt,idx,tp,n,m; void add(int u,int v) { edge[ecnt].u = u; edge[ecnt].v = v; edge[ecnt].next = head[u]; head[u] = ecnt++; } int judge(int x,int y) { if(x>=0&&y>=0&&x<n&&y<m)return x*m+y+1; return 0; } void build() { int i,j,k = 1,x; ecnt = cnt = idx = tp = 0; MSET(head,-1); for(i = 0; i < n; ++ i) for(j = 0; j < m; ++ j) scanf("%d",&as[i][j]); for(i = 0; i < n; ++ i) for(j = 0; j < m; ++ j) { k = i*m+j+1; for(x = 0; x < 4; ++ x) { int ii = i + dx[x]; int jj = j + dy[x]; int t = judge(ii,jj); if(t&&as[i][j]>=as[ii][jj]) add(k,t); } } } void tarjan(int x) { int i,v,top = 0,u; zha[++top] = x; while(top) { u = zha[top]; if(!vis[u]){ st[++tp] = u; vis[u] = 1; } if(!dfn[u]) dfn[u]=low[u]=++idx; for(; cur[u]!=-1; cur[u]=edge[cur[u]].next){ v = edge[cur[u]].v; if(dfn[v]){ if(vis[v]) low[u] = min(low[u],dfn[v]); continue; } zha[++top] = v; break; } if((cur[u]==-1)&&(dfn[u]==low[u])){ ++cnt; do{ v = st[tp--]; vis[v] = 0; belong[v] = cnt; }while(v!=u); } if(zha[top]==u){ --top; v = zha[top]; if(top) low[v] = min(low[v],low[u]); } } } void processing() { int i,j,k,t,u,v; while(cin>>m>>n) { build(); MSET(vis,0); MSET(dfn,0); MSET(belong,0); MSET(in,0); MSET(out,0); for(i = 1; i <= n * m; ++ i) cur[i] = head[i]; for(i = 1; i <= n * m; ++ i) if(!dfn[i]) tarjan(i); if(cnt==1){puts("0");continue;} for(i = 0; i < ecnt; ++ i) { u = belong[edge[i].u]; v = belong[edge[i].v]; if(v!=u){out[u]++; in[v]++;} } k = 0; t = 0; for(i = 1; i <= cnt; ++ i) { if(!out[i])k++; if(!in[i]) t++; } printf("%d\n",max(k,t)); } } int main() { processing(); return 0; }