1. 程式人生 > 實用技巧 >Yoi #379. 淘淘藍藍之樹林

Yoi #379. 淘淘藍藍之樹林

題面


分析

要求的是某個點到圖上的點的兩條方向不同的路徑的長度的最小和

所以加入一條邊阻斷,答案為到邊上的點左邊和右邊+2的最小值
注意加入的邊不能經過起點

#include<bits/stdc++.h>
const int INF=1e9;
using namespace std;

const int N=2005;
int n,m,f[N][N],qx[N*N],qy[N*N],l,r;
char a[N][N];
int dx[8]={-1,-1,-1,0,0,1,1,1};
int dy[8]={-1,0,1,-1,1,-1,0,1};

int main() {
	freopen("forest.in","r",stdin);
        freopen("forest.out","w",stdout);
	scanf("%d%d",&n,&m); int sx=0,sy=0,tx=0,ty;
	for(int i=1;i<=n;i++) {
		scanf("%s",a[i]+1);
		for(int j=1;j<=m;j++) {
			if(a[i][j]=='*') sx=i,sy=j;
			if(a[i][j]=='X'&&j!=sy&&!tx) tx=i,ty=j;
		}
	}
	bool fl=0;
	if(tx==0) {
		fl=1;
		for(int i=n;i;i--) {
			for(int j=m;j;j--) {
				if(a[i][j]=='X'&&!tx) tx=i,ty=j;
			}
		}
		for(int i=tx+1;i<=n;i++)a[i][ty]='X';
	} else for(int i=1;i<tx;i++) a[i][ty]='X';
	for(int i=0;i<=n+1;i++) {
		for(int j=0;j<=m+1;j++) f[i][j]=INF;
	}
	f[sx][sy]=0;
	qx[l=r=1]=sx,qy[1]=sy;
	while(l<=r) {
		int x=qx[l],y=qy[l]; l++;
		for(int i=0;i<8;i++) {
			int xx=x+dx[i],yy=y+dy[i];
			if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&a[xx][yy]!='X'&&f[x][y]+1<f[xx][yy]) {
				f[xx][yy]=f[x][y]+1;
				qx[++r]=xx,qy[r]=yy;
			}
		}
	}
	int ans=INF;
	if(!fl)
	for(int i=1;i<tx;i++) {
		ans=min(ans,min(f[i][ty-1],min(f[i-1][ty-1],f[i+1][ty-1]))+min(f[i][ty+1],min(f[i-1][ty+1],f[i+1][ty+1]))+2);
	} else {
		for(int i=tx+1;i<=n;i++) {
			ans=min(ans,min(f[i][ty-1],min(f[i-1][ty-1],f[i+1][ty-1]))+min(f[i][ty+1],min(f[i-1][ty+1],f[i+1][ty+1]))+2);
	}
		
	}
	printf("%d\n",ans);
	return 0;
}