石油大--2020年秋季組隊訓練賽第十三場----B、Bouldering(最短路)

_Shmily發表於2020-09-28

題面:
在這裡插入圖片描述

題意:
給定一個 h ∗ w h*w hw 點陣,其中某一些點是可以走的。
這些點都有一個權值,表示如果經過當前點,則會花費的力氣。
給定一個 r r r,你只能從當前點到達與你歐幾里得距離不超過 r r r 的點。
問在花費的總力氣不超過 s s s 的情況下,從最下層的那個點(保證唯一),走到最上層的那個點(保證唯一)距離的最小值。

題解:
對於花費的力氣的總值為: w ∗ h ∗ 9 w*h*9 wh9,是一個較小的值。
我們可以設 d p [ x ] [ j ] dp[x][j] dp[x][j] 為當前走到 x x x 號節點,花費力氣為 j j j 的最短距離。

然而這樣直接寫會 T L E TLE TLE ,因為會走到很多無用的狀態。

考慮剪枝,如果當前到達 x x x 的最短路是 d i s dis dis,在當前 d i s dis dis 下花費的力氣為 k k k,那麼那些 d i s ′ > = d i s   a n d   k ′ > = k dis'>=dis\ and\ k'>=k dis>=dis and k>=k 的狀態都是無用的,跳過即可。只有 d i s ′ > = d i s   a n d   k ′ < k dis'>=dis\ and\ k'<k dis>=dis and k<k 的那些狀態才可能對於最終答案有貢獻。

#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<unordered_map>
#include<set>
namespace onlyzhao
{
    #define ui unsigned int
    #define ll long long
    #define llu unsigned ll
    #define ld long double
    #define pr make_pair
    #define pb push_back
    #define lc (cnt<<1)
    #define rc (cnt<<1|1)
    #define len(x)  (t[(x)].r-t[(x)].l+1)
    #define tmid ((l+r)>>1)
    #define fhead(x) for(int i=head[(x)];i;i=nt[i])
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)>(y)?(y):(x))
    #define one(n) for(int i=1;i<=(n);i++)
    #define rone(n) for(int i=(n);i>=1;i--)
    #define fone(i,x,n) for(int i=(x);i<=(n);i++)
    #define frone(i,n,x) for(int i=(n);i>=(x);i--)
    #define fonk(i,x,n,k) for(int i=(x);i<=(n);i+=(k))
    #define fronk(i,n,x,k) for(int i=(n);i>=(x);i-=(k))
    #define two(n,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
    #define ftwo(i,n,j,m) for(int i=1;i<=(n);i++) for(int j=1;j<=(m);j++)
    #define fvc(vc) for(int i=0;i<vc.size();i++)
    #define frvc(vc) for(int i=vc.size()-1;i>=0;i--)
    #define forvc(i,vc) for(int i=0;i<vc.size();i++)
    #define forrvc(i,vc) for(int i=vc.size()-1;i>=0;i--)
    #define cls(a) memset(a,0,sizeof(a))
    #define cls1(a) memset(a,-1,sizeof(a))
    #define clsmax(a) memset(a,0x3f,sizeof(a))
    #define clsmin(a) memset(a,0x80,sizeof(a))
    #define cln(a,num) memset(a,0,sizeof(a[0])*num)
    #define cln1(a,num) memset(a,-1,sizeof(a[0])*num)
    #define clnmax(a,num) memset(a,0x3f,sizeof(a[0])*num)
    #define clnmin(a,num) memset(a,0x80,sizeof(a[0])*num)
    #define sc(x) scanf("%d",&x)
    #define sc2(x,y) scanf("%d%d",&x,&y)
    #define sc3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define scl(x) scanf("%lld",&x)
    #define scl2(x,y) scanf("%lld%lld",&x,&y)
    #define scl3(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)
    #define scf(x) scanf("%lf",&x)
    #define scf2(x,y) scanf("%lf%lf",&x,&y)
    #define scf3(x,y,z) scanf("%lf%lf%lf",&x,&y,&z)
    #define scs(x) scanf("%s",x+1)
    #define scs0(x) scanf("%s",x)
    #define scline(x) scanf("%[^\n]%*c",x+1)
    #define scline0(x) scanf("%[^\n]%*c",x)
    #define pcc(x) putchar(x)
    #define pc(x) printf("%d\n",x)
    #define pc2(x,y) printf("%d %d\n",x,y)
    #define pc3(x,y,z) printf("%d %d %d\n",x,y,z)
    #define pck(x) printf("%d ",x)
    #define pcl(x) printf("%lld\n",x)
    #define pcl2(x,y) printf("%lld %lld\n",x,y)
    #define pcl3(x,y,z) printf("%lld %lld %d\n",x,y,z)
    #define pclk(x) printf("%lld ",x)
    #define pcf2(x) printf("%.2f\n",x)
    #define pcf6(x) printf("%.6f\n",x)
    #define pcf8(x) printf("%.8f\n",x)
    #define pcs(x) printf("%s\n",x+1)
    #define pcs0(x) printf("%s\n",x)
    #define pcline(x) printf("%d**********\n",x)
    #define casett int tt;sc(tt);int pp=0;while(tt--)

    char buffer[100001],*S,*T;
    inline char Get_Char()
    {
        if (S==T)
        {
            T=(S=buffer)+fread(buffer,1,100001,stdin);
            if (S==T) return EOF;
        }
        return *S++;
    }
    inline int read()
    {
        char c;int re=0;
        for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
        while(c>='0'&&c<='9') re=re*10+(c-'0'),c=Get_Char();
        return re;
    }
};
using namespace onlyzhao;
using namespace std;

const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e9;
const int mod=998244353;
const double eps=1e-9;
const double pi=acos(-1.0);
const int hp=13331;
const int maxn=1000100;
const int maxm=100100;
const int up=100100;

double dp[25*25+100][25*25*9+100];
bool ha[25*25+100][25*25*9+100];
int h,w,r,ss;

pair<int,int>p[25*25+100],s,t;
pair<double,int>pp[25*25+100];
int cnt=0,ans=0;
char str[55][55];

int head[maxn],ver[maxn],nt[maxn],val[maxn],tot=1;
double edge[maxn];

void add(int x,int y,double z)
{
    ver[++tot]=y,edge[tot]=z;
    nt[tot]=head[x],head[x]=tot;
}

int p2(int x)
{
    return x*x;
}

int dis(int i,int j)
{
    return p2(p[i].first-p[j].first)+p2(p[i].second-p[j].second);
}

int sgn(double x)
{
    if(abs(x)<eps) return 0;
    else if(x>0) return 1;
    else return -1;
}

struct node
{
    double dis;
    int x,val;
    friend bool operator < (const node &a,const node &b)
    {
        if(sgn(a.dis-b.dis)!=0) return a.dis>b.dis;
        return a.val>b.val;
    }
    node(){}
    node(double a,int b,int c)
    {
        dis=a,x=b,val=c;
    }

};

void dij(int s)
{
    for(int i=1;i<=cnt;i++)
    {
        for(int j=0;j<=ans;j++)
            dp[i][j]=dnf,ha[i][j]=false;
    }
    dp[s][val[s]]=0;
    priority_queue<node> q;
    q.push(node(0.0,s,val[s]));
    while(q.size())
    {
        int x=q.top().x;
        int vv=q.top().val;
        q.pop();

        if(ha[x][vv]) continue;
        ha[x][vv]=true;

        if(pp[x].first>dp[x][vv])
        {
            pp[x].first=dp[x][vv];
            pp[x].second=vv;
        }

        for(int i=head[x];i;i=nt[i])
        {
            int y=ver[i];
            double z=edge[i];
            int nowc=val[y];

            if(vv+nowc>ans) continue;
            if(dp[x][vv]+z>=pp[y].first&&vv+nowc>=pp[y].second) continue;

            if(dp[y][vv+nowc]>dp[x][vv]+z)
            {
                dp[y][vv+nowc]=dp[x][vv]+z;
                q.push(node(dp[y][vv+nowc],y,vv+nowc));
            }
        }
    }
}

int main(void)
{
    scanf("%d%d%d%d",&h,&w,&r,&ss);
    s.first=-1;
    t.first=inf;
    for(int i=1;i<=h;i++)
    {
        scanf("%s",str[i]+1);
        for(int j=1;j<=w;j++)
        {
            if(str[i][j]=='.') continue;
            str[i][j]-='0';
            ans+=str[i][j];
            p[++cnt]=pr(i,j);
            val[cnt]=str[i][j];

            if(p[cnt].first>s.first)
            {
                s.first=p[cnt].first;
                s.second=cnt;
            }
            if(p[cnt].first<t.first)
            {
                t.first=p[cnt].first;
                t.second=cnt;
            }
        }
    }
    ans=min(ans,ss);
    for(int i=1;i<=cnt;i++)
    {
        pp[i].first=dnf;
        for(int j=1;j<=cnt;j++)
        {
            if(i==j) continue;
            if(dis(i,j)>r*r) continue;
            add(i,j,sqrt(dis(i,j)));
            add(j,i,sqrt(dis(i,j)));
        }
    }

    dij(s.second);
    int tt=t.second;
    double minn=dnf;
    for(int i=0;i<=ans&&i<=ss;i++)
        minn=min(minn,dp[tt][i]);

    if(minn+10>=dnf) printf("impossible\n");
    else printf("%.15f\n",minn);
    return 0;
}


相關文章