自闭的ACM

112 篇文章 0 订阅

这里写图片描述
这里写图片描述
首先,一种新颖的方法叫“建图求最短路”,给每个点能到达的点连上单向边,跑dijkstra,但是边的数量太大了,领接表都存不下,所以又一种新颖的做法叫“云里雾里dijkstra”(摘自题解):
取图中最远可能弹射的距离H。(H<=N+M-2)
引入“云端”这个新概念。
我们建立一个包含NM(S+1)个点的图dis[1…N][1…M][0…S]
其中dis[x][y][0]代表地面,也就是原图的街区。
dis[x][y][h]代表一个云端节点。
当居民在云端节点上时,他必须选择往低一层的相邻云端降落。
也就是说,dis[x][y][h]有5条出边:
dis[x][y][h]到dis[x][y][h-1]
dis[x][y][h]到dis[x-1][y][h-1]
dis[x][y][h]到dis[x+1][y][h-1]
dis[x][y][h]到dis[x][y-1][h-1]
dis[x][y][h]到dis[x][y+1][h-1]
它们的边权都是0.
也就是说,在高度为1的云端可以降落到地面的5个相邻节点。
弹射装置的作用实际上就是把飞飞侠从地面弹到同经纬的一定高度的云端上(所以你想,从那个高度一直往下走五个方向,走到地面形成的范围就正好是弹射装置能弹射的范围,所以向下走权值为0)。
如果a[x][y]=v(弹射能力),那么我们建边dis[x][y][0]到dis[x][y][v],边权(长度)为b[x][y](弹射费用)。
这样一来每个云端点只有5条出边,每个地面点只有一条出边,也就是说,这是一个相当稀疏的图,点数和边数同级,我们建立了一个点数和边数都是O(NMS)的图,同样是求3个地面点相互的最短路。
这题和BZOJ上的飞飞侠有点相似,BZOJ能过但zr只有90

#include<bits/stdc++.h>
using namespace std;
int getint()
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;isdigit(ch);ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}
const int maxn=205;
const int fx[5]={0,-1,0,1,0};
const int fy[5]={1,0,-1,0,0};
int n,m,H;
int a[maxn][maxn],b[maxn][maxn];
long long dis[maxn][maxn][maxn*2],cost[4][4];
struct node{
    int x,y,h;
    friend inline bool operator < (const node &a,const node &b)
    {
        return a.h<b.h;
    }
}hom[4];
priority_queue<pair<long long,node> > que;
void dijkstra(int s,int t1,int t2)
{
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            for(int k=0;k<=H;++k)
                dis[i][j][k]=1e18;
    int x,y,d,h;
    bool bz1=0,bz2=0;
    while(!que.empty()) que.pop();
    x=hom[s].x,y=hom[s].y,h=hom[s].h;
    dis[x][y][h]=b[x][y];
    que.push(make_pair(-dis[x][y][h],(node){x,y,h}));
    while(!que.empty())
    {
        node u=que.top().second;
        que.pop();
        x=u.x,y=u.y,h=u.h;
        d=dis[x][y][h];
        if(x==hom[t1].x&&y==hom[t1].y&&h==0) bz1=1,cost[s][t1]=d;
        if(x==hom[t2].x&&y==hom[t2].y&&h==0) bz2=1,cost[s][t2]=d;
        if(bz1&&bz2) return;
        if(h>0)
            for(int i=0;i<5;++i)
            {
                int newx=x+fx[i],newy=y+fy[i];
                if(newx>=1&&newx<=n&&newy>=1&&newy<=m)
                    if(dis[newx][newy][h-1]>d)
                    {
                        dis[newx][newy][h-1]=d;
                        que.push(make_pair(-dis[newx][newy][h-1],(node){newx,newy,h-1}));
                    }
            }
        else
        {
            h=a[x][y];
            if(dis[x][y][h]>d+b[x][y])
            {
                dis[x][y][h]=d+b[x][y];
                que.push(make_pair(-dis[x][y][h],(node){x,y,h}));
            }
        }
    }
}
int main()
{
    n=getint(),m=getint();
    H=n+m-2;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            a[i][j]=getint(),a[i][j]=min(a[i][j],H);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            b[i][j]=getint();
    for(int i=1;i<=3;++i)
        hom[i].x=getint(),hom[i].y=getint(),hom[i].h=a[hom[i].x][hom[i].y];
    for(int i=1;i<=3;++i)
        for(int j=1;j<=3;++j)
            cost[i][j]=1e18;
    dijkstra(1,2,3);
    dijkstra(2,1,3);
    dijkstra(3,1,2); 
    long long ans=1e18;char ch;
    if(cost[2][1]+cost[3][1]<ans) ans=cost[2][1]+cost[3][1],ch='X';
    if(cost[1][2]+cost[3][2]<ans) ans=cost[1][2]+cost[3][2],ch='Y';
    if(cost[1][3]+cost[2][3]<ans) ans=cost[1][3]+cost[2][3],ch='Z';
    if(ans==1e18) cout<<"NO"<<'\n';
    else cout<<ch<<'\n'<<ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值