bzoj 3388: [Usaco2004 Dec]Cow Ski Area雪场缆车(Tarjan)

3388: [Usaco2004 Dec]Cow Ski Area雪场缆车

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 108   Solved: 47
[ Submit][ Status][ Discuss]

Description

    约翰的表哥罗恩生活在科罗拉多州.他近来打算教他的奶牛们滑雪,但是奶牛们非常害羞,
不敢在游人如织的度假胜地滑雪.没办法,他只好自己建滑雪场了.罗恩的雪场可以划分为W列L行(1≤W≤500;1≤L≤500),每个方格有一个特定的高度H(O≤日≤9999).奶牛可以在相临方格间滑雪,而且不能由低到高滑.    为了保证任意方格可以互通,罗恩打算造一些直达缆车.缆车很强大,可以连接任意两个方格,而且是双向的.而且同一个方格也可以造多台缆车.但是缆车的建造费用贵得吓人,所以他希望造尽量少的缆车.那最少需要造多少台呢?

Input

  第1行:W,L.
  接下来输入宽W高L的矩阵地图.

Output

    最小的缆车数.

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


如过相邻的两个格子x和y满足a[x]>=a[y],那么x到y连一条有向边

之后强连通分量缩点,答案就是max(入度为0的点的个数,出度为0的点的个数)

注意特判答案为0的情况!


#include<stdio.h>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
vector<int> G[250005], G2[250005];
stack<int> st;
int num, t, time[250005], in[250005], out[250005], vis[250005], low[250005], scc[250005], a[505][505], dir[4][2] = {1,0,0,1,-1,0,0,-1};
void Trajan(int x)
{
	int i, temp;
	st.push(x);
	vis[x] = 1;
	low[x] = time[x] = ++t;
	for(i=0;i<G[x].size();i++)
	{
		temp = G[x][i];
		if(vis[temp]==0)
		{
			Trajan(temp);
			low[x] = min(low[x], low[temp]);
		}
		else if(scc[temp]==0)
			low[x] = min(low[x], time[temp]);
	}
	if(low[x]==time[x])
	{
		num++;
		while(st.empty()==0)
		{
			temp = st.top();
			st.pop();
			scc[temp] = num;
			if(temp==x)
				break;
		}
	}
}
int main(void)
{
	int n, m, i, j, k, x, y, temp;
	scanf("%d%d", &m, &n);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
			scanf("%d", &a[i][j]);
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			for(k=0;k<=3;k++)
			{
				x = i+dir[k][0];
				y = j+dir[k][1];
				if(x>=1 && x<=n && y>=1 && y<=m && a[x][y]<=a[i][j])
					G[(i-1)*m+j].push_back((x-1)*m+y);
			}
		}
	}
	for(i=1;i<=n*m;i++)
	{
		if(vis[i]==0)
			Trajan(i);
	}
	for(i=1;i<=n*m;i++)
	{
		for(j=0;j<G[i].size();j++)
		{
			temp = G[i][j];
			if(scc[i]!=scc[temp])
				G2[scc[i]].push_back(scc[temp]);
		}
	}
	if(num==1)
		printf("0\n");
	else
	{
		for(i=1;i<=num;i++)
		{
			out[i] = G2[i].size();
			for(j=0;j<G2[i].size();j++)
				in[G2[i][j]]++;
		}
		x = y = 0;
		for(i=1;i<=num;i++)
		{
			if(out[i]==0)
				x++;
			if(in[i]==0)
				y++;
		}
		printf("%d\n", max(x, y));
	}
	return 0;
}
/*
3 3
1 1 1
1 2 1
1 1 1
*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值