题目链接 Cow Ski Area
题意
好吧,还是看了各种翻译才看懂的。说的是一个人要自己建滑雪场 ,每个滑雪场都是一个一个方格,在输入中也就是一个数字(这个数字也就是这个滑雪场的高度),现在告诉你,每两个相邻的滑雪场可以直接从高的滑雪场通向低的滑雪场,低的不能通向高的滑雪场。除此之外没有别的通路。为了使得最后能从某任意一个滑雪场通向任意一个滑雪场,这个人会建一些路,这样才能使得低高度的滑雪场通向高的滑雪场。现在问你最少需要修建的路的条数。
思路
很明显我们需要先把能互相通向的强联通图给分别求出来。缩完后,然后分别求出点的入度和出度为0 的点的个数。他们的最大值就是最终的答案。以前的存图方式是vector模拟邻接表,在这里总是超时,可能是我算法的缘故,后来改成链式前向星,终于过了,再就是这题G++似乎会RE,C++就过了,还有就是RE也可能是数组开小了,比如说我,因为这个RE到QAQ。
#include <stdio.h>
#include <iostream>
#include <map>
#include <algorithm>
#include <queue>
#include <string>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 250001;
int scc,index,top,In,belong[maxn],Out,dfn[maxn],low[maxn],Stack[maxn];
int vis[maxn],in[maxn],out[maxn];
int a[501][501];
int n,m;
struct node{
int to,next;
}Edge[1100001];
int tot,head[maxn];
int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-')
{
f = -1;
}
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x*f;
}
void add(int from,int to)
{
Edge[tot].to = to;
Edge[tot].next = head[from];
head[from] = tot++;
}
void tarjan(int x)
{
int i,v,j;
dfn[x] = low[x] = ++index;
vis[x] = 1;
Stack[++top] = x;
for(j = head[x]; j != -1; j = Edge[j].next)
{
v = Edge[j].to;
if(!dfn[v])
{
tarjan(v);
low[x] = min(low[x],low[v]);
}
else if(vis[v])
{
low[x] = min(low[x],dfn[v]);
}
}
if(dfn[x] == low[x])
{
scc++;
do{
v = Stack[top--];
vis[v] = 0;
belong[v] = scc;
}while(v != x);
}
}
void init()
{
memset(vis,0,sizeof(vis));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(belong,0,sizeof(belong));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
}
void solve()
{
int i,j,v;
for(i = 1; i <= n * m; ++i)
{
for(j = head[i]; j != -1; j = Edge[j].next)
{
v = Edge[j].to;
if(belong[i] != belong[v])
{
out[belong[i]]++;
in[belong[v]]++;
}
}
}
for(int i = 1; i <= scc; ++i)
{
if(!in[i])
In++;
if(!out[i])
Out++;
}
if(scc == 1)
printf("0\n");
else
printf("%d\n",max(In,Out));
}
void check(int x,int y,int ans)
{
if(x > 1)
{
if(a[x][y] >= a[x - 1][y])
{
add(ans,ans - m);
}
}
if(x < n)
{
if(a[x][y] >= a[x + 1][y])
add(ans,ans + m);
}
if(y > 1)
{
if(a[x][y] >= a[x][y - 1])
add(ans,ans - 1);
}
if(y < m)
{
if(a[x][y] >= a[x][y + 1])
add(ans,ans + 1);
}
}
int main()
{
m = read();
n = read();
init();
memset(head,-1,sizeof(head));
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m; ++j)
{
a[i][j] = read();
}
}
tot = 1;
int ans = 1;
for(int i = 1;i <= n; ++i)
for(int j = 1; j <= m ;++j)
{
check(i,j,ans++);
}
scc = 0;
index = 0;
top = 0;
In = 0;
Out = 0;
for(int i = 1; i <= n * m ; ++i)
{
if(!dfn[i])
tarjan(i);
}
solve();
}