題意,給你一個l,和一個地圖,讓你從起點走到終點,使得路程剛好等於l。 你可以選擇一個系數,把縱向的地圖拉伸或收縮,比如你選擇系數0.5,也就是說現在上下走一步消耗0.5的距離,如果選擇系數3,也就是說上下一步消耗3的距離。 左右不能改變。 Hint中提示了答案在0--10之間,其實就透露出了二分的思想。 我們對系數P進行二分,對每一個系數P進行一次bfs,如果可以在小於等於l的步數內找到解,則增加下界,否則減小上界。 由於上下和左右的消耗值不相同,所以我們采用A*算法,設估價值為當前點到目標點的哈弗曼距離(注意上下距離要乘上系數P),然後利用優先隊列搜索。 我試了幾下,精度開到1e-6才不會wa
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #include<iostream> using namespace std; char map[105][105]; int CAS; double l; int n,len; int end,st; int dx[]={-1,1,0,0}; int dy[]={0,0,-1,1}; struct node { double dis; int x; int y; double h; bool operator < (const node &a) const { return dis+h>a.dis+h; } }start; double geth(int x,int y,double k) { double h=0; int ex=end/len; int ey=end%len; return abs(ey-y)+abs(ex-x)*k; } bool isok(int x,int y) { return x>=0&&x<n&&y>=0&&y<len&&map[x][y]!='#'; } double vis[105][105]; bool bfs(double k) { for(int i=0;i<n;i++) for(int j=0;j<len;j++) vis[i][j]=100000000; priority_queue<node> q; q.push(start); vis[start.x][start.y]=1; node tmp,tt; while(!q.empty()) { tmp=q.top();q.pop(); for(int d=0;d<4;d++) { tt=tmp; tt.x=tmp.x+dx[d]; tt.y=tmp.y+dy[d]; if(isok(tt.x,tt.y)) { tt.h=geth(tt.x,tt.y,k); if(d<=1) tt.dis+=k; else tt.dis+=1; if(tt.dis<vis[tt.x][tt.y]) vis[tt.x][tt.y]=tt.dis; else continue; if(tt.x==end/len&&tt.y==end%len) { if(tt.dis<=l) return true; else return false; } q.push(tt); } } } return false; } int main() { int cas; CAS=1; scanf("%d",&cas); while(cas--) { scanf("%lf%d",&l,&n);getchar(); for(int i=0;i<n;i++) gets(map[i]); len=strlen(map[0]); for(int i=0;i<n;i++) for(int j=0;j<len;j++) { if(map[i][j]=='S') { st=i*len+j; } if(map[i][j]=='E') { end=i*len+j; } } start.dis=0; start.x=st/len; start.y=st%len; double l=0; double r=11; double mid=(l+r)/2.0; while(r-l>1e-6) { // cout<<l<<' '<<r<<' '<<mid<<endl; mid=(l+r)/2.0; if(bfs(mid)) l=mid; else r=mid; } printf("Case #%d: %.3f%%\n",CAS++,mid*100); } return 0; }