Cow Ski Area
Time Limit: 1000MS |
|
Memory Limit: 65536K |
Total Submissions: 3137 |
|
Accepted: 872 |
Description
Farmer John's cousin, Farmer Ron, who lives in the mountains of Colorado, has recently taught his cows to ski. Unfortunately, his cows are somewhat timid and are afraid to ski among crowds of people at the local resorts, so FR has decided to construct his
own private ski area behind his farm.
FR's ski area is a rectangle of width W and length L of 'land squares' (1 <= W <= 500; 1 <= L <= 500). Each land square is an integral height H above sea level (0 <= H <= 9,999). Cows can ski horizontally and vertically between any two adjacent land squares,
but never diagonally. Cows can ski from a higher square to a lower square but not the other way and they can ski either direction between two adjacent squares of the same height.
FR wants to build his ski area so that his cows can travel between any two squares by a combination of skiing (as described above) and ski lifts. A ski lift can be built between any two squares of the ski area, regardless of height. Ski lifts are bidirectional.
Ski lifts can cross over each other since they can be built at varying heights above the ground, and multiple ski lifts can begin or end at the same square. Since ski lifts are expensive to build, FR wants to minimize the number of ski lifts he has to build
to allow his cows to travel between all squares of his ski area.
Find the minimum number of ski lifts required to ensure the cows can travel from any square to any other square via a combination of skiing and lifts.
Input
* Line 1: Two space-separated integers: W and L
* Lines 2..L+1: L lines, each with W space-separated integers corresponding to the height of each square of land.
Output
* Line 1: A single integer equal to the minimal number of ski lifts FR needs to build to ensure that his cows can travel from any square to any other square via a combination of skiing and ski lifts
Sample Input
9 3
1 1 1 2 2 2 1 1 1
1 2 1 2 3 2 1 2 1
1 1 1 2 2 2 1 1 1
Sample Output
3
Hint
This problem has huge input data,use scanf() instead of cin to read data to avoid time limit exceed.
OUTPUT DETAILS:
FR builds the three lifts. Using (1, 1) as the lower-left corner,
the lifts are (3, 1) <-> (8, 2), (7, 3) <-> (5, 2), and (1, 3) <->
(2, 2). All locations are now connected. For example, a cow wishing
to travel from (9, 1) to (2, 2) would ski (9, 1) -> (8, 1) -> (7,
1) -> (7, 2) -> (7, 3), take the lift from (7, 3) -> (5, 2), ski
(5, 2) -> (4, 2) -> (3, 2) -> (3, 3) -> (2, 3) -> (1, 3), and then
take the lift from (1, 3) - > (2, 2). There is no solution using
fewer than three lifts.
题目大意:给你一个矩阵,代表一个滑雪场,滑雪场中每个点都能向四周四个方向移动,但是移动的地方一定是要值比当前点的值小于等于才行。然后我们可以建缆车,使得值低的地方也能到值高的地方,要你求的是这样一个问题:最少构建多少个缆车,使得任意选取一个点作为起点,都能到达整个滑雪场的任意一个点。
思路:
1、首先考虑如何建边(对样例进行详解)。
建边其实没有想象的那么困难,首先我们对每个格子都进行节点编号:
1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18
19 20 21 22 23 24 25 26 27
然后对于每个节点,我们都对其周围四个点进行判断,是否能够走到,如果能够走到,直接建边即可。
对于这个图,我们建出来的边有这些:
1 2
1 10
2 3
2 1
3 2
3 12
4 5
4 3
4 13
5 6
5 4
6 7
6 5
6 15
7 8
7 16
8 9
8 7
9 8
9 18
10 19
10 1
11 12
11 10
11 20
11 2
12 21
12 3
13 12
13 22
13 4
14 15
14 13
14 23
14 5
15 16
15 24
15 6
16 25
16 7
17 18
17 16
17 26
17 8
18 27
18 9
19 20
19 10
20 21
20 19
21 20
21 12
22 23
22 21
22 13
23 24
23 22
24 25
24 23
24 15
25 26
25 16
26 27
26 25
27 26
27 18
2、然后我们在求强连通分量和缩点之前,分析在DAG图下的这个问题。
我们首先来观察一个强连通分量为1的图【注意看箭头方向】:
图1:
对于有向边,我们有入度和出度的定义。在上图中,每个节点的入度和出度都是1.也同时说明,对于一个强连通分量为1的图,出度和入度两种度中,一定两种度都没有0度的存在。我们不妨在观察一个强连通分量为1的图:
其1的出度:2,入度2。
其2的出度:1,入度1。
其3的出度:1,入度1.
我们再观察一个强连通分量不是1的图:
其1的出度为2,入度为0
其2的出度为0,入度为1
其3的出度为0,入度为1
那么我们要将这个图变成强连通分量为1的图,我们不妨这样考虑:既然强连通分量为1的图有这样的特点:如果一个图是强连通分量为1的图,对于每个节点来说,一定没有任何一个点的出度或者入度有0的情况。那么我们的任务也就明确了,对于所有节点度的处理,使得没有0度的存在。
那么我们对上图再进行分析,这里设出度为0的节点数为a,设入度为0的节点数为b,其实我们如果找到了a和b的值,搞定最大值,其实也就搞定了这个问题。
那么最终得到这样的结论:设定output=max(a,b),假设output=a,那么就对出度为0的节点,一共连a条边,这些边都从出度为0的节点出发,到应该到的地方去。最终一定能使得图的出度和入度没有度为0的节点存在,同理,如果output=b,也能够达成目标。
3、既然得到了结论,下一个动作就是做题啦~,因为图是会存在有向环的,所以我们使用Kosaraju算法来求出强连通分量,然后对所有属于一个强连通分量的点缩点看成一个点进行染色,然后统计入度出度,得到结果。
AC代码:
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
int head[250050];
int head2[250050];
struct EdgeNode
{
int from;
int to;
int next;
}e[250050*5],ee[250050*5];
int n,m,cont,cont2,sig;
int a[515][515];
int fx[4]={0,0,1,-1};
int fy[4]={1,-1,0,0};
int in[250050];
int out[250050];
int vis[250050];
int num[250050];
int color[250050];
void add(int from,int to)
{
e[cont].from=from;
e[cont].to=to;
e[cont].next=head[from];
head[from]=cont++;
}
void add2(int from,int to)
{
ee[cont2].from=from;
ee[cont2].to=to;
ee[cont2].next=head2[from];
head2[from]=cont2++;
}
void init()
{
cont=0;
cont2=0;
memset(vis,0,sizeof(vis));
memset(out,0,sizeof(out));
memset(in,0,sizeof(in));
memset(head,-1,sizeof(head));
memset(head2,-1,sizeof(head2));
memset(color,0,sizeof(color));
memset(num,0,sizeof(num));
}
void Dfs(int u)
{
vis[u]=1;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(vis[v]==0)
{
Dfs(v);
}
}
num[sig++]=u;
}
void Dfs2(int u)
{
vis[u]=1;
color[u]=sig;
for(int i=head2[u];i!=-1;i=ee[i].next)
{
int v=ee[i].to;
if(vis[v]==0)
{
Dfs2(v);
}
}
}
void Kosaraju(int n)
{
sig=1;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
Dfs(i);
}
}
sig=0;
memset(vis,0,sizeof(vis));
for(int i=n;i>=1;i--)
{
if(vis[num[i]]==0)
{
sig++;
Dfs2(num[i]);
}
}
if(sig==1)
{
printf("0\n");
return ;
}
for(int i=1;i<=n;i++)
{
for(int k=head[i];k!=-1;k=e[k].next)
{
int u=i,v=e[k].to;
if(color[u]!=color[v])
{
out[color[u]]++;
in[color[v]]++;
}
}
}
int ruu=0;
int chu=0;
for(int i=1;i<=sig;i++)
{
if(in[i]==0)ruu++;
if(out[i]==0)chu++;
}
printf("%d\n",max(ruu,chu));
}
int main()
{
while(~scanf("%d%d",&m,&n))
{
init();
int maxn=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=0;k<4;k++)
{
int xx=fx[k]+i;
int yy=fy[k]+j;
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&a[xx][yy]<=a[i][j])
{
//printf("%d %d\n",(i-1)*m+j,(xx-1)*m+yy);
add((i-1)*m+j,(xx-1)*m+yy);
add2((xx-1)*m+yy,(i-1)*m+j);
}
}
}
}
Kosaraju(n*m);
}
}