zoukankan      html  css  js  c++  java
  • 最小生成树Kruskal+LCA+bfs【bzoj4242】水壶

    Description

    JOI 君所居住的 IOI 市以一年四季都十分炎热著称。

    IOI 市被分成 (H) 行,每行包含 (W) 块区域。每个区域都是建筑物、原野、墙壁之一。
    IOI 市有 (P) 个区域是建筑物,坐标分别为 ((A_1, B_1)(A_2, B_2)dots(A_P, B_P))
    JOI 君只能进入建筑物与原野,而且每次只能走到相邻的区域中,且不能移动到市外。

    JOI 君因为各种各样的事情,必须在各个建筑物之间往返。虽然建筑物中的冷气设备非常好,但原野上太阳非常毒辣,因此在原野上每走过一个区域都需要 1 升水。此外,原野上没有诸如自动售货机、饮水处之类的东西,因此 IOI 市的市民一般都携带水壶出行。大小为 (x) 的水壶最多可以装 (x) 升水,建筑物里有自来水可以将水壶装满。
    由于携带大水壶是一件很困难的事情,因此 JOI 君决定携带尽量小的水壶移动。因此,为了随时能在建筑物之间移动,请你帮他写一个程序来计算最少需要多大的水壶。

    现在给出 IOI 市的地图和 (Q) 个询问,第 (i) 个询问包含两个整数 (S_i, T_i),对于每个询问,请输出:要从建筑物 (S_i)移动到 (T_i),至少需要多大的水壶?

    Input

    第一行四个空格分隔的整数 (H,W,P,Q.) 接下来 (H) 行,第 (i) 行有一个长度为 (W) 的字符串,每个字符都是 . 或 # 之一,. 表示这个位置是建筑物或原野,# 表示这个位置是墙壁。 接下来 (P) 行描述 IOI 市每个建筑物的位置,第 (i) 行有两个空格分隔的整数 (A_i) 和 (B_i),表示第 (i) 个建筑物的位置在第 (A_i) 行第 (B_i) 列。保证这个位置在地图中是 .。 接下来 (Q) 行,第 (i) 行有两个空格分隔的整数 (S_i, T_i)

    Output

    输出 (Q) 行,第 (i) 行一个整数,表示要从建筑物 (S_i) 移动到 (T_i),至少需要多大的水壶。 如果无法到达,输出 -1。如果不需要经过原野就能到达,输出 0

    一道好题。货车运输的既视感.

    难点在于建边,我们可以从建筑物向外扩展,这时候,如果扩展出来的地方相互接触,则可以直接对中心的建筑物之间直接建边即可.具体建边的话见我的大佬同桌王小呆的博客

    建边出来跑(Kruskal),然后跑维护最大值的带权(LCA)即可。

    代码

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<queue>
    #include<iostream>
    #define N 2008
    #define R register
    using namespace std;
    inline void in(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    struct cod{int x,y;};
    int n,m,P,Q;
    int res[N][N],dis[N][N];
    int vis[N][N],fa[200008];
    const int ax[]={0,0,-1,1};
    const int ay[]={1,-1,0,0};
    int head[4000018],tot,ttt,cnt;
    struct code{int u,v,w;}edge[5000018],e[5000018];
    char s[N+2];
    inline void add(int x,int y,int z)
    {
    	e[++ttt].u=head[x];
    	e[ttt].v=y;
    	e[ttt].w=z;
    	head[x]=ttt;
    }
    inline bool ccp(const code&a,const code&b)
    {
    	return a.w<b.w;
    }
    queue<cod>q;
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    inline int bfs()
    {
    	while(!q.empty())
    	{
    		int x=q.front().x,y=q.front().y;
    		q.pop();
    		for(R int i=0;i<4;i++)
    		{
    			int nx=x+ax[i],ny=y+ay[i];
    			if(nx<1 or nx>n or ny>m or ny<1 or res[nx][ny])continue;
    			if(dis[nx][ny]==-1)
    			{
    				vis[nx][ny]=vis[x][y];
    				dis[nx][ny]=dis[x][y]+1;
    				q.push((cod){nx,ny});
    			}
    			else if(vis[nx][ny]!=vis[x][y])
    			{
    				edge[++tot].u=vis[nx][ny];
    				edge[tot].v=vis[x][y];
    				edge[tot].w=dis[x][y]+dis[nx][ny];
    			}
    		}
    	}
    }
    inline void kruskal()
    {
    	sort(edge+1,edge+tot+1,ccp);
    	for(R int i=1;i<=tot;i++)
    	{
    		R int u=edge[i].u,v=edge[i].v,w=edge[i].w;
    		R int fu=find(u),fv=find(v);
    		if(fu==fv)continue;
    		fa[fu]=fv;add(fu,fv,w);add(fv,fu,w);cnt++;
    		if(cnt==P-1)break;
    	}
    }
    int gw[200008][21],f[200008][21],depth[400008];
    void dfs(int u,int fa,int dis)
    {
    	f[u][0]=fa;gw[u][0]=dis;depth[u]=depth[fa]+1;
    	for(R int i=1;(1<<i)<=depth[u];i++)
    	{
    		f[u][i]=f[f[u][i-1]][i-1];
    		gw[u][i]=max(gw[u][i-1],gw[f[u][i-1]][i-1]);
    	}
    	for(R int i=head[u];i;i=e[i].u)
    	{
    		if(e[i].v==fa)continue;
    		dfs(e[i].v,u,e[i].w);
    	}
    }
    inline int lca(int x,int y)
    {
    	int res=-2147483644;
    	if(depth[x]>depth[y])swap(x,y);
    	for(R int i=20;i>=0;i--)
    		if(depth[x]+(1<<i)<=depth[y])
    			res=max(res,gw[y][i]),y=f[y][i];
    	if(x==y)return res;
    	for(R int i=20;i>=0;i--)
    	{
    		if(f[x][i]==f[y][i])continue;
    		res=max(res,max(gw[x][i],gw[y][i]));
    		y=f[y][i],x=f[x][i];
    	}
    	return max(res,max(gw[x][0],gw[y][0]));
    }
    int main()
    {
    	in(n),in(m),in(P),in(Q);
    	for(R int i=1;i<=n;i++)
    	{
    		scanf("%s",s+1);
    		for(R int j=1;j<=m;j++)
    		{	
    			res[i][j]= s[j]=='#';
    			dis[i][j]=-1;
    		}
    	}
    	for(R int i=1,x,y;i<=P;i++)
    	{
    		in(x),in(y);fa[i]=i;
    		dis[x][y]=0;vis[x][y]=i;
    		q.push((cod){x,y});
    	}
    	bfs();
    	kruskal();
    	for(R int i=1;i<=P;i++)
    		if(!f[i][0])dfs(i,0,0);
    	for(R int i=1,x,y;i<=Q;i++)
    	{
    		in(x),in(y);
    		if(find(x)!=find(y))puts("-1");
    		else printf("%d
    ",lca(x,y));
    	}
    }
    
  • 相关阅读:
    TypeScript reflect-metadata 结合方法装饰器实现的一个自定义语法检查的例子
    使用 TypeScript 自定义装饰器给类的方法增添监听器 Listener
    爬取本blog所有文章链接
    90分钟掌握Python多线程爬虫(全程实战)
    python学习笔记
    Python零基础爬虫教学(实战案例手把手Python爬虫教学)
    开发,功能测试点,注意
    workerman
    tp6 文档
    公共方法
  • 原文地址:https://www.cnblogs.com/-guz/p/9817392.html
Copyright © 2011-2022 走看看