Stronger Takahashi

Stronger Takahashi

题意:

​ 从(1,1)走到(h,w)的最短耗费,s(i,j)为‘.’表示可走,为‘#’表示有阻挡物,我们可以耗费1去打通一个相邻2*2的方块,无论这个方块是否可以走通都可以变成能走通

思路:建图+spfa最短路

​ 假设他在需要之前不打孔,我们可以假设一个2×2破坏块区域与高桥所在的正方形相邻。当高桥位于下图中标记的T的正方形中时,在打孔一次后,他可以移动到标记为*的任何正方形,不管方块的先前状态如何。

.***.
*****
**T**
*****
.***.

代码:

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=250010;
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
int f[N],dis[N],vis[N];
int h,w,cnt,id;
int p[510][510];
char c[510][510];
int e[N<<5],ww[N<<5],ne[N<<5];
void add(int x,int y,int v){
	e[++id]=x;
	ww[id]=v;
	ne[id]=f[y];
	f[y]=id;
}
bool check(int x,int y){
	if(x>h||x<1||y>w||y<1) return false;
	return true;
}
struct cmp
{
    bool operator()(int a,int b)
    {
        return dis[a]>dis[b];
    }
};
void spfa(){
	vis[1]=1;
	priority_queue<int,vector<int>,cmp> q;
	q.push(1);
	dis[1]=0;
	while(q.size()){
		int t=q.top();
		q.pop();
		vis[t]=0;
		for(int i=f[t];~i;i=ne[i]){
			int k=e[i];
			if(dis[k]>dis[t]+ww[i]){
				dis[k]=dis[t]+ww[i];
				if(vis[k]==0){
					q.push(k);
					vis[k]=1;
				}
			}
		}
	}
}

signed main(){
	memset(f,-1,sizeof f);
	memset(vis,0,sizeof vis);
	memset(dis,0x3f,sizeof dis);
	cin>>h>>w;
	for(int i=1;i<=h;i++){
		for(int j=1;j<=w;j++){
			cin>>c[i][j];
			p[i][j]=++cnt;
		}
	} 
	for(int i=1;i<=h;i++){
		for(int j=1;j<=w;j++){
			//表示周围是可行的,费用为0 
			for(int k=0;k<4;k++){
				int xx=i+dx[k],yy=j+dy[k];
				if(check(xx,yy)&&c[xx][yy]!='#'){
					add(p[xx][yy],p[i][j],0);
				}
			}
			//表示在这个点打了墙费用为1 
			for(int k=-2;k<=2;k++){
				for(int kk=-2;kk<=2;kk++){
					if(abs(k)==2&&abs(kk)==2) continue;
					int xx=i+k,yy=j+kk;
					if(check(xx,yy)){
						add(p[xx][yy],p[i][j],1);
					}
				}
			}
		}
	}
	spfa();//跑最短路 
	cout<<dis[p[h][w]]<<endl;
} 

posted @ 2021-09-05 21:39  Curry_BP  阅读(35)  评论(0)    收藏  举报