BZOJ 1295: [SCOI2009]最长距离

题目大意:

给定一张网格图,求图上删掉T个障碍物之后能联通的两点的最大欧几里德距离是多少。

题解:

预处理两点间路径经过的最小障碍物数,判断是否小于T,更新答案。

代码:

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#define mp make_pair
#define pr pair<int,int>
#define sc second
using namespace std;
int n,m,T,cnt,dis[905],vis[905],f[905][905],a[35][35],last[905];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
char s[35];
struct node{
	int to,next,val;
}e[10005];
priority_queue<pr,vector<pr>,greater<pr> > q;
int calc(int x,int y){
	return (x-1)*m+y;
}
void Dijkstra(int st){
	for (int i=1; i<=n*m; i++) dis[i]=1e9,vis[i]=0;
	dis[st]=0;
	q.push(mp(0,st));
	while (!q.empty()){
		int x=q.top().sc;
		q.pop();
		if (vis[x]) continue;
		vis[x]=1;
		for (int i=last[x]; i; i=e[i].next){
			int V=e[i].to;
			if (dis[V]>dis[x]+e[i].val){
				dis[V]=dis[x]+e[i].val;
				q.push(mp(dis[V],V));
			}
		}
	}
	for (int i=1; i<=n*m; i++) f[st][i]=dis[i];
}
void add(int a,int b,int c){
	e[++cnt].to=b;
	e[cnt].next=last[a];
	e[cnt].val=c;
	last[a]=cnt;
}
int main(){
	scanf("%d%d%d",&n,&m,&T);
	for (int i=1; i<=n; i++){
		scanf("%s",s+1);
		for (int j=1; j<=m; j++)
			if (s[j]=='1') a[i][j]=1;
	}
	for (int i=1; i<=n; i++)
		for (int j=1; j<=m; j++)
			for (int k=0; k<4; k++){
				int fx=i+dx[k],fy=j+dy[k];
				if (fx<1 || fx>n || fy<1 || fy>m) continue;
				add(calc(i,j),calc(fx,fy),a[fx][fy]);
			}
	for (int i=1; i<=n; i++)
		for (int j=1; j<=m; j++)
			Dijkstra(calc(i,j));
	for (int i=1; i<=n; i++)
		for (int j=1; j<=m; j++)
			if (a[i][j]){
				for (int k=1; k<=n*m; k++)
					f[calc(i,j)][k]++;
			}
	double maxx=0;
	for (int x1=1; x1<=n; x1++)
		for (int y1=1; y1<=m; y1++)
			for (int x2=1; x2<=n; x2++)
				for (int y2=1; y2<=m; y2++)
					if (f[calc(x1,y1)][calc(x2,y2)]<=T) maxx=max(maxx,sqrt((double)(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)));
	printf("%lf
",maxx);
	return 0;
}

  

原文地址:https://www.cnblogs.com/silenty/p/8744789.html