题目链接:
http://poj.org/problem?id=3897
题目意思:
求竖直伸缩比例,使得从起点到终点的距离最小值恰好等于给定值。
未伸缩前水平和竖直的步长都为1。
解题思路:
二分伸缩比例,用BFS求在该竖直长度下的最短距离,直到该距离等于给定值。
搜索的时候,用优先队列来确定搜索位置,使得每次搜索都是从距离开始点的最短距离开始往后搜
代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-8
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
using namespace std;
/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
char save[120][120];
double dis[120][120];
bool flag[120][120];
double sd;
int dir[4][2]={-1,0,0,1,1,0,0,-1};
int n,m;
struct Point
{
int x,y;
}ss,ee;
struct Inf
{
double len;
Point p;
friend bool operator <(Inf a,Inf b) //是优先队列中对头为最小的距离
{
return a.len>b.len;
}
};
priority_queue<Inf>myp;
bool iscan(Point xx)
{
if(xx.x<0||xx.x>n||xx.y<0||xx.y>m)
return false;
return true;
}
bool equal(Point a,Point b)
{
if(a.x==b.x&&a.y==b.y)
return true;
return false;
}
double BFS(double yy) //每次搜索都是从距离开始点的最短距离开始往后搜
{
//myp.clear();
while(!myp.empty())
myp.pop();
Inf s;
s.p=ss,s.len=0;
myp.push(s);
memset(flag,false,sizeof(flag));
flag[(s.p).x][(s.p).y]=1;
while(!myp.empty())
{
Inf ff=myp.top(); //表示到达该位置的最短距离
myp.pop();
for(int i=0;i<4;i++)
{
Point pp;
pp.x=(ff.p).x+dir[i][0],pp.y=(ff.p).y+dir[i][1];
if(!iscan(pp))
continue;
if(flag[pp.x][pp.y])
continue;
if(save[pp.x][pp.y]!=' ')
continue;
Inf tmp=ff;
tmp.p=pp;
tmp.len=tmp.len+((i&1)?1:yy);
if(equal(ee,pp)) //找到了最短距离
return tmp.len;
flag[pp.x][pp.y]=1;
myp.push(tmp);
}
}
}
int main()
{
int t;
scanf("%d",&t);
for(int ca=1;ca<=t;ca++)
{
scanf("%lf%d",&sd,&n);
getchar();
for(int i=1;i<=n;i++)
{
gets(save[i]+1);
//printf("%s\n",save[i]+1);
for(int j=1;save[i][j];j++)
{
if(save[i][j]=='S')
{
ss.x=i,ss.y=j;
save[i][j]=' '; //把起点和终点 置为可访问状态
}
else if(save[i][j]=='E')
{
ee.x=i,ee.y=j;
save[i][j]=' ';
}
}
}
//printf("%d %d %d %d\n",ss.x,ss.y,ee.x,ee.y);
m=strlen(save[1]+1);
//printf("%d %d\n",n,m);
double l=0,r=1000,mid,ans;
while(fabs(r-l)>eps)
{
mid=(l+r)/2;
double tt=BFS(mid);
//printf("%lf\n",tt);
if(sd-tt>eps) //小了,往上放
{
ans=mid;
l=mid;
}
else
r=mid; //大了,不行往下收
}
printf("Case #%d: %0.3lf%%\n",ca,ans*100);
}
return 0;
}