题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5652
题目大意:
在n*m的矩阵里面,放值为1的山峰。当山峰连起来能够封锁整个m列的时候,问最早是什么时候。
范围:
n,m<=500,Q<=n*m。
思路:
可以用并查集存下每个点能向左延伸的距离和向右延伸的距离。当有一个点为1的时候,看他8个方向是否有为1的山峰,如果有就将他们并入同一个集合,然后更新他们的最左和最右。当能够封锁的时候,就是答案。
代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,x[250500],y[250500];
struct node{
int l,r,num;
}p[5500005];
char s[505][505];
void init()
{
int i,j;
for(i=0;i<=505;i++)
for(j=0;j<=505;j++)
{
p[i*1000+j].l=j;
p[i*1000+j].r=j;
p[i*1000+j].num=1000*i+j; //初始化将点化为数。
}
return ;
}
int findroot(int x)
{
int r=x;
while(r!=p[r].num)
r=p[r].num;
int i=x,j;
while(i!=r)
{
j=p[i].num;
p[i].num=r;
i=j;
}
return r;
}
int join(int x,int y)
{
int fx,fy;
fx=findroot(x);
fy=findroot(y);
if(fx<fy){
p[fy].num=fx;
int mi,ma;
mi=min(min(p[y].l,p[fx].l),min(p[x].l,p[fy].l));
ma=max(max(p[y].r,p[fx].r),max(p[x].r,p[fy].r));
p[fy].l=p[x].l=p[y].l=p[fx].l=mi;
p[fy].r=p[x].r=p[y].r=p[fx].r=ma;
return fx;
}
else {
p[fx].num=fy;
int mi,ma;
mi=min(min(p[y].l,p[fx].l),min(p[x].l,p[fy].l));
ma=max(max(p[y].r,p[fx].r),max(p[x].r,p[fy].r));
p[fy].l=p[x].l=p[y].l=p[fx].l=mi;
p[fy].r=p[x].r=p[y].r=p[fx].r=ma;
return fy;
}
}
void judge(int x,int y)
{
int a,b;
if(s[x][y+1]==1&&y+1<=m){
a=x*1000+y;
b=x*1000+y+1;
int mi=join(a,b);
}
if(s[x+1][y+1]==1&&x+1<=n&&y+1<=m){
a=x*1000+y;
b=(x+1)*1000+y+1;
int mi=join(a,b);
}
if(s[x+1][y]==1&&x+1<=n){
a=x*1000+y;
b=(x+1)*1000+y;
int mi=join(a,b);
}
if(s[x+1][y-1]==1&&x+1<=n&&y-1>0)
{
a=x*1000+y;
b=(x+1)*1000+y-1;
int mi=join(a,b);
}
if(s[x][y-1]==1&&y-1>0)
{
a=x*1000+y;
b=(x)*1000+y-1;
int mi=join(a,b);
}
if(s[x-1][y-1]==1&&x-1>0&&y-1>0)
{
a=x*1000+y;
b=(x-1)*1000+y-1;
int mi=join(a,b);
}
if(s[x-1][y]==1&&x-1>0){
a=x*1000+y;
b=(x-1)*1000+y;
int mi=join(a,b);
}
if(s[x-1][y+1]==1&&x-1>0&&y+1<=m)
{
a=x*1000+y;
b=(x-1)*1000+y+1;
int mi=join(a,b);
}
}
int main()
{
int T,i,j,k,Q;
scanf("%d",&T);
while(T--)
{
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
for(i=0;i<505;i++)
for(j=0;j<505;j++)
s[i][j]=0;
init();
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
cin>>s[i][j];
s[i][j]-='0';
}
int ff=0;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
if(s[i][j]==1){
judge(i,j);
int aa=i*1000+j;
aa=findroot(aa);
if(p[aa].r-p[aa].l==m-1){
ff=1;
break;
}
}
}
scanf("%d",&Q);
for(i=1;i<=Q;i++)
scanf("%d%d",&x[i],&y[i]);
if(ff){
printf("0\n");
continue;
}
int f=0;
for(i=1;i<=Q;i++)
{
s[x[i]+1][y[i]+1]=1;
judge(x[i]+1,y[i]+1);
int fx;
fx=findroot((x[i]+1)*1000+y[i]+1);
if(p[fx].r-p[fx].l==m-1){
printf("%d\n",i);
f=1;
break;
}
}
if(f==0)printf("-1\n");
}
}
/*
3 3
010
000
010
5
0 0
1 0
0 2
1 1
2 0
*/

本文介绍了一个使用并查集算法解决山峰封锁问题的方法。在一个n*m的矩阵中,通过放置值为1的山峰,并利用并查集记录每个山峰向左右两侧的延伸距离,当山峰能封锁整列时,即可找到最早时刻。
&spm=1001.2101.3001.5002&articleId=50997227&d=1&t=3&u=f38dc6092426406aa681efff1a91ac8b)
132

被折叠的 条评论
为什么被折叠?



