3388: [Usaco2004 Dec]Cow Ski Area雪场缆车
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 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
*/