时间限制: 1000 ms 空间限制: 262144 KB 具体限制
题目描述
众所周知,TerryHu 是一位大佬,他平时最喜欢做的事就是蒸发学水。
机房的位置一共有n 行m 列,一开始每个位置都有一滴学水,TerryHu 决定在每一个时刻选择
一滴学水进行蒸发,直到机房里不再存在学水。
TerryHu 想知道在每个时刻之后,机房里剩下的学水构成了几个联通块
输入
第一行包含2 个正整数n,m。
之后n 行每行包含m 个正整数Ai;j,表示第i 行第j 列的学水在时刻Ai;j 被蒸发,保证{A}
构成了一个n *m 的排列。
输出
共n * m 行每行包含1 个整数ansi,时刻i 之后剩下的学水构成的联通块的数量。
样例输入
2 2 1 3 4 2
样例输出
1 2 1 0
数据范围限制
数据范围:
对于60%
的数据:n,m<= 50;
对于100%
的数据:n,m<= 1000。
首先,我们可以用宽搜(广搜)去解
#include<iostream>//蒸发学水
using namespace std;
int n,m,ans,f,mp[1001][1001],a[1000001][2],d[1000001][2];
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
void go(int x,int y)
{
ans++;
f++;
mp[x][y]=2;
int t=0,w=1,xx,yy;
d[1][0]=x;
d[1][1]=y;
do
{
t++;
for(int i=0;i<=3;i++)
{
xx=d[t][0]+dx[i];
yy=d[t][1]+dy[i];
if(xx>0&&xx<=n&&yy>0&&yy<=m&&mp[xx][yy]==0)
{
w++;
d[w][0]=xx;
d[w][1]=yy;
mp[xx][yy]=2;
f++;
}
}
}while(t<w);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>f;
a[f][0]=i;
a[f][1]=j;
}
for(int k=1;k<=n*m;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(mp[i][j]==2)
mp[i][j]=0;
}
}
mp[a[k][0]][a[k][1]]=1;
ans=0;
f=k;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(f==n*m)
{
break;
}
else if(mp[i][j]==0)
{
go(i,j);
}
}
if(f==n*m)
break;
}
cout<<ans<<endl;
}
}
但我们发现,只能的60分,但我也没办法
才怪
并查集啊啊啊啊啊啊啊啊啊啊啊啊啊啊
#include<bits/stdc++.h>
using namespace std;
int f1[1000110],f2[1000110],fa[1000110],ans[1000110],a[1010][1010],tot=0;//f1记录行 f2记录列 fa记录祖先 ans记录当前位子的连通块的情况
bool b[1010][1010];//标记当前行列的水的状态 0是已经蒸发 1是没蒸发
int fx[5]={0,1,0,-1,0};
int fy[5]={0,0,1,0,-1};
int find(int i)//并查集 的查找
{
if(fa[i]==i)
return i;
else
{
fa[i]=find(fa[i]);
return fa[i];
}
}
int unionn(int x,int y)//合并
{
int xfa=find(x);
int yfa=find(y);
fa[xfa]=yfa;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
f1[a[i][j]]=i;
f2[a[i][j]]=j;
}
for(int i=n*m;i>=1;i--)
{
int x=f1[i];
int y=f2[i];
b[x][y]=1;
fa[x*m+y]=x*m+y;//并查集的初始化祖先
tot++;
for(int j=1;j<=4;j++)
{
int xx=x+fx[j];
int yy=y+fy[j];
if(xx>=1 and xx<=n and yy>=1 and yy<=m and b[xx][yy]==1 and find(xx*m+yy)!=find(x*m+y))
{
unionn(x*m+y,xx*m+yy);
tot--;
}
}
ans[i]=tot;
}
for(int i=2;i<=n*m+1;i++) printf("%d\n",ans[i]);
return 0;
}
387ms 20mb
当然还有网传方法
#include <iostream>
using namespace std;
const int MAXSIZE = 1000*1000+1;
int uset[MAXSIZE];
int answer[MAXSIZE];
pair<short,short> valueToIndex[MAXSIZE];
const int dx[]={-1,0,0,1},dy[]={0,-1,1,0};
//void makeSet(int size) {
// for(int i = 1;i <= size;i++) uset[i] = -MAXSIZE;
//}
int find(int x) {
int p = x, t;
while (uset[p] > 0) p = uset[p];
while (x != p ) {
t = uset[x];
uset[x] = p;
x = t;
}
return x;
}
void unionSet(int x, int y) {
if ((x = find(x)) == (y = find(y))) return;
if (uset[x] < uset[y]) {
uset[x] += uset[y];
uset[y] = x;
} else {
uset[y] += uset[x];
uset[x] = y;
}
}
void unionSetRoot(int x,int y)
{
if (uset[x] < uset[y]) {
uset[x] += uset[y];
uset[y] = x;
} else {
uset[y] += uset[x];
uset[x] = y;
}
}
int raw,col;
int main()
{
scanf("%d%d",&raw,&col);
int size = raw * col;
//makeSet(size);
for(short i=1;i<=raw;i++)
for(short j=1;j<=col;j++)
{
int value;
scanf("%d",&value);
valueToIndex[value] = make_pair(i,j);
}
for(int evaWater=size-1;evaWater>=1;evaWater--)
{
int lastEvaWater = evaWater+1;
int x = valueToIndex[lastEvaWater].first;
int y = valueToIndex[lastEvaWater].second;
int lastValueIndex = (x-1)*col +y;
uset[lastValueIndex] = -1;
answer[evaWater] = answer[lastEvaWater]+1;
for(int dir=0;dir<4;dir++)
{
int tx=x+dx[dir],ty=y+dy[dir];
if(tx >=1&& tx <=raw && ty>=1 && ty<= col )
{
int los =(tx-1)*col+ty;
if( uset[los] !=0 )
{
int key = find(los);
int last = find(lastValueIndex);
if(last != key)
{
unionSetRoot(last,key);
answer[evaWater]--;
}
}
}
}
}
for (int i=1;i<=size;i++)
printf("%d\n",answer[i]);
return 0;
}
才343ms!!!!!