poj2375Cow Ski Area

Cow Ski Area
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 3885 Accepted: 1022

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
题意:本题描述了一片滑雪场,并且规定奶牛从一个点只能向它相邻的并且高度不大于它的点运动,现在想要在某些点对之间加上缆车使得奶牛也可以从较低点到达较高点,问最少需要多少辆这样的缆车就可以使得奶牛可以从任意一个点运动到滑雪场的每个角落。

思路:建图,然后tarjan缩点,统计入度和出度为0的个数,取两者最大值就好了。

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
#include <vector>
using namespace std;
const int N=510;
int dfn[N*N],low[N*N],belong[N*N];
bool instack[N*N];
int head[N*N];
int in[N*N],out[N*N];
int cnt,index,num;
struct edge
{
    int v,next;
}e[N*N*8];
int f[510][510];
int dir[4][2]={1,0,-1,0,0,1,0,-1};
stack<int>s;
int m,n;
void addedge(int u,int v)
{
    e[num].v=v;
    e[num].next=head[u];
    head[u]=num++;
}
void init()
{
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
     memset(in,0,sizeof(in));
      memset(out,0,sizeof(out));
    memset(belong,0,sizeof(belong));
    memset(instack,false,sizeof(instack));
    memset(head,-1,sizeof(head));
    while(!s.empty())s.pop();

    num=cnt=index=0;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++index;
    instack[u]=true;
    s.push(u);
    int v;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        v=e[i].v;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(instack[v])
        {
            low[u]=min(dfn[v],low[u]);
        }
    }
    if(low[u]==dfn[u])
    {
        cnt++;
        do{
                v=s.top();
                s.pop();
                belong[v]=cnt;
                instack[v]=false;

        }while(u!=v);
    }
}
int main()
{
    while(~scanf("%d%d",&m,&n))
    {
        int i,j;
        for(i=0;i<n;i++)
        {
            for(j=0;j<m;j++)
            {
                scanf("%d",&f[i][j]);
            }
        }
        init();
        for(i=0;i<n;i++)
    {
        for(j=0;j<m;j++)
        {
            for(int 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;
                int u=i*m+j;
                int v=nx*m+ny;
                if(f[i][j]>=f[nx][ny])
                {
                    addedge(u,v);
                }
                if(f[i][j]<=f[nx][ny])
                {
                   addedge(v,u);
                }
            }
        }
    }
        for(i=0;i<m*n;i++)
        {
            if(!dfn[i])
            {
                tarjan(i);
            }

        }
        if(cnt==1)
        {
            printf("0\n");
            continue;
        }
        for(i=0;i<m*n;i++)
        {
            for(j=head[i];j!=-1;j=e[j].next)
            {
                int v=e[j].v;
                if(belong[i]!=belong[v])
                {
                    in[belong[v]]++;
                    out[belong[i]]++;
                }
            }
        }
        int ans=0,ans1=0;
        for(i=1;i<=cnt;i++)
        {
            if(in[i]==0)
            {
                ans++;
            }
            if(out[i]==0)
            {
                ans1++;
            }
        }
        printf("%d\n",max(ans,ans1));
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值