Cpp环境【POJ 2375】【Vijos1642】雪场缆车

【问题描述】  

  约翰的表哥罗恩生活在科罗拉多州。他进来打算教他的奶牛们滑雪,但是奶牛们非常害羞,不敢在游人如织的度假胜地滑雪。没办法,他只好自己建滑雪场了。

  罗恩的雪场可以划分为W列L行,每个方格都有一个特定的高度H。奶牛可以在相邻邻方格间滑雪,而且不能由低到高滑。

  为了保证任意方格可以互通,罗恩打算造一些直达缆车。缆车很强大,可以连接任意两个方格,而且是双向的。而且同一个方格可以造多台缆车。但是缆车的建造费用贵的吓人,所以他希望造尽量少的缆车。那最少需要多少台呢?

【输入格式】  

  第一行:W和L
  接下来是W*H的矩阵地图。

【输出格式】  

  最小的缆车数

【输入样例】  

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

【输出样例】  

3

【样例解释】  

  把左下角作为(1,1),建立(3,1) <->(8,2),(7,3)<->(5,2),(1,3)<->(2,2)三部缆车,这样任意两个格子可以互通。

【数据范围】  

1<=W<=500;1<=L<=500
0<=H<=9999

【来源】    

POJ 2375

【思路梳理】

运用缩点的思想,可以将每一片高度相同的区域可以都看做是一个连通分量,那么在输入图之后对整张图进行处理。因为只能由高度不低于该点的格子移动过来,那么我们可以从高度更高的区域向低的区域连一条有向边。添加缆车就是加一条无向边,使得两个端点所处的区域相互连通。由此观之,我们要向整个图中添加无向边(准确来说应该是双向有向边),使得有向图中所有的连通分量都全部相互强连通。给出cpp代码如下。

【Cpp代码】
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#define maxn 505
using namespace std;
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
struct loca
{
    int x,y;
};
int w,l,height[maxn][maxn],belong[maxn][maxn],scc=0;
int cd[maxn*maxn],rd[maxn*maxn];
vector<int>g[maxn*maxn];

void read(int &x)
{
    x=0;char ch=getchar();
    while(ch<'0' || ch>'9') ch=getchar();
    while(ch>='0' && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
}

loca q[250005];int front,rear;
void BFS(int x,int y,int scc)
{
    front=rear=1;
    q[rear++]=(loca){x,y};
    belong[x][y]=scc;

    while(front!=rear)
    {
        x=q[front].x,y=q[front].y;front++;

        for(int i=0;i<4;i++)
        {
            int xx=x+dx[i],yy=y+dy[i];
            if(belong[xx][yy] || xx<1 || xx>w || yy<1 || yy>l)  continue;
            if(height[xx][yy]==height[x][y])
            {
                q[rear++]=(loca){xx,yy};
                belong[xx][yy]=scc;
            }               
        }
    } 
}

int main()
{
//  freopen("in.txt","r",stdin);
    read(l);read(w);
    for(int i=1;i<=w;i++)
    for(int j=1;j<=l;j++)   read(height[i][j]);

    for(int i=1;i<=w;i++)
    for(int j=1;j<=l;j++)if(!belong[i][j])
        BFS(i,j,++scc);

    for(int i=1;i<=w;i++)
    for(int j=1;j<=l;j++)
    for(int k=0;k<4;k++)
    {
        int x=i+dx[k],y=j+dy[k];
        if(x>w || x<1 || y>l || y<1)    continue;
        if(height[x][y]<height[i][j])
        {
            cd[belong[i][j]]++;
            rd[belong[x][y]]++;
        }
        else if(height[x][y]>height[i][j])
        {
            rd[belong[i][j]]++;
            cd[belong[x][y]]++;
        }
    }

    int a=0,b=0,ans=0;
    for(int i=1;i<=scc;i++)
    {
        if(rd[i]==0)    a++;
        if(cd[i]==0)    b++;
    }
    if(scc==1)  ans=0;
    else ans=max(a,b);
    cout<<ans;
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值