P6245 [USACO06OPEN]The Climbing Wall S [Dijkstra算法]

https://www.luogu.com.cn/problem/P6245
最短路
黄色题
思路:
(题解第一个)
1.主要是一种虚拟点的思想,因为无法确定起点和终点
2.题目要求的是步数,与原模板题的距离不同,所以要把距离替换成步数。

代码:
#include<cmath>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<vector>
#define pii pair<int,int>//宏定义,个人习惯
using namespace std;
struct Node
{
    int head,dis;
    double x,y;
    //横坐标和纵坐标
}node[10005];
struct Edge
{
    int next,to,len;
}edge[99990005];
int h,f;
//与题目意义相同
bool cmp(Node a,Node b)
{
    if(a.y==b.y)return a.x<b.x;
    return a.y<b.y;
}
//排序函数,方便对点进行处理
double calc(double x_1,double y_1,double x_2,double y_2)
{
    return double(sqrt((x_1-x_2)*(x_1-x_2)+(y_1-y_2)*(y_1-y_2)));
}
//求距离
int cnt;
void addEdge(int u,int v,int w)
{
    edge[++cnt].len=w;
    edge[cnt].next=node[u].head;
    edge[cnt].to=v;
    node[u].head=cnt;
}
//链式前向星存图
void Dijkstra()
{
    for(int i=0;i<=f+1;i++) node[i].dis=0x3f3f3f3f;
    //别忘了初始化
    priority_queue<pii,vector<pii>,greater<pii> >q;
    //STL小根堆
    node[0].dis=0;
    q.push({0,0});
    while(q.size())
    {
        pii tmp=q.top();
        q.pop();
        int d=tmp.first,u=tmp.second;
        if(d!=node[u].dis)continue;
        for(int e=node[u].head;e;e=edge[e].next)
        {
            int v=edge[e].to;
            if(node[v].dis>d+edge[e].len)
            {
                node[v].dis=d+edge[e].len;
                q.push({node[v].dis,v});
            }
        }
    }
}
//模板
int main()
{
    scanf("%d%d",&h,&f);
    for(int i=1;i<=f;i++)
    {
        scanf("%lf%lf",&node[i].x,&node[i].y);
    }
    sort(node+1,node+f+1,cmp);
    //排序
    for(int i=1;i<=f;i++)
    {
        for(int j=i+1;j<=f;j++)
        {
            double dist=calc(node[i].x,node[i].y,node[j].x,node[j].y);
            //求得距离
            if(dist<=1000)
            {
                //如果两个点间的距离不超过1000,
                //就可以直接到达
                //建立权值为1的边
                //表示爬一次
                addEdge(i,j,1);
                addEdge(j,i,1);
            }
        }
        if(h-node[i].y<1000)
        {
            //与最大距离H不到1000的点可以直接到达终点
            //那么就与虚拟终点连一条边
            addEdge(i,f+1,1);
            addEdge(f+1,i,1);
            //虚拟终点就是f+1
        }
        if(node[i].y<=1000)
        {
            //与地面距离不超过1000的点可以作为起点
            //那么就与虚拟起点连一条边
            addEdge(0,i,0);
            addEdge(i,0,0);
            //虚拟起点就是0
        }
    }
    Dijkstra();
    printf("%d\n",node[f+1].dis);
    //这里注意输出的是虚拟终点的距离
    return 0;
}

 

posted @ 2022-08-02 14:30  -イレイナ  阅读(54)  评论(0)    收藏  举报