您的位置:首页 > 其它

POJ2375 暴力建图+tarjan缩点

2018-03-29 19:17 344 查看
POJ2375
题意:
给一个n*m,n,m<=500的格子滑雪场,每个格子有个海拔,可以上下左右滑,
海拔高的可以滑到海拔低的,海拔相同的可以互相滑
现在要建若干电梯(选两个格子使其可以互相到达,无海拔限制)
使得从任意一个点出发都可以经过整个滑雪场
问最少需要建多少个电梯
思路:
其实就是问最少加多少条边使得整个图变成强连通图
对于缩点后的DAG
入度为0 的点的数目 ,出度为0的点的数目之间的较大值就是答案了
(画几个图体会体会)
如果一开始已经是强连通就输出0
建图直接暴力!
坑点:
g++ re,c++wa,数组开800才过
282ms#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=805;
const int maxe=640005;
int low[maxn*maxn];
int dfn[maxn*maxn];
bool ins[maxn*maxn];
int sk[maxn*maxn];
int poi=0,idx=0,cnt=0;
int num=0;
int head[maxn*maxn];
int to[maxe*2];
int nxt[maxe*2];

//bool vis[505][505];
int mp[605][605];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
int n,m;
int in[maxn*maxn];//入度
int ou[maxn*maxn];//出度
int scc[maxn*maxn];
void add(int u,int v)
{
cnt++;nxt[cnt]=head[u];
head[u]=cnt; to[cnt]=v;
}
void dfs(int x,int y)
{
// if(vis[x][y]==1)return ;
// vis[x][y]=1;
for(int i=0;i<=3;i++)
{
int tx=x+dx[i];
int ty=y+dy[i];
if(tx<1||tx>n||ty<1||ty>m)continue;
// printf("%d %d %d %d\n",x,y,tx,ty);
if(mp[tx][ty]<=mp[x][y])
add((x-1)*m+y,(tx-1)*m+ty);//printf("???");//m:lie
// if(mp[tx][ty]==mp[x][y])
// add((x-1)*m+y,(tx-1)*m+ty),add((tx-1)*m+ty,(x-1)*m+y);
//if(vis[tx][ty]==0&&mp[tx][ty]<=mp[x][y])
// dfs(tx,ty);
}
}

void tarjan(int u)
{
dfn[u]=low[u]=++idx;
ins[u]=1;
sk[poi++]=u;
for(int i=head[u];i!=-1;i=nxt[i])
{
int v=to[i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
num++;
int t;
do{
t=sk[--poi];
scc[t]=num;
ins[t]=0;
}
while(t!=u);
}
}

int main()
{
scanf("%d %d",&m,&n);

memset(ins,0,sizeof(ins));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(head,-1,sizeof(head));
memset(ou,0,sizeof(ou));
memset(in,0,sizeof(in));
// memset(vis,0,sizeof(vis));
num=poi=cnt=idx=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mp[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
dfs(i,j);
/*
for(int u=1;u<=n*m;u++)
{
printf("dian u:%d :",u);
for(int
4000
i=head[u];i!=-1;i=nxt[i])
printf(" %d",to[i]);
puts("");
}*/

for(int i=1;i<=n*m;i++)
{
if(!dfn[i])
tarjan(i);
}
int ans=0;
for(int u=1;u<=n*m;u++)
{
for(int i=head[u];i!=-1;i=nxt[i])
{
int v=to[i];
if(scc[u]!=scc[v])
{
ou[scc[u]]++;
in[scc[v]]++;
}
}
}
// printf("num:%d\n",num);
if(num==1)
printf("0\n");
else
{
int ans1=0;int ans2=0;
for(int i=1;i<=num;i++)
{
if(in[i]==0)ans1++;
if(ou[i]==0)ans2++;
}
printf("%d\n",max(ans1,ans2));
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: