4152: [AMPPZ2014]The Captain

题目链接

题目大意:平面上的n个点,(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用

题解:首先,忽视min,直接建两条边即可。考虑到从x1->x2的路径,直达一定比绕过另一个点短(从式子很容易看出来),于是按x/y排两次序,相邻的连边即可

我的收获:这个似乎是常见的套路……

#include <cstdio>  
#include <cstring>  
#include <cstdlib>  
#include <cmath>  
#include <iostream>  
#include <algorithm>  
#include <queue>  
using namespace std;  
 
#define M 200010   
#define INF 1e60
#define pii pair<long long,int>  
 
int n,t,head[M];  
long long dis[M];   
bool vis[M];
 
struct point{int x,y,id;}a[M];  
struct edge{int to,val,nex;}e[M*4];
 
priority_queue<pii,vector<pii>,greater<pii> > q;  
 
bool cmpx(point a,point b){return a.x<b.x;}  
bool cmpy(point a,point b){return a.y<b.y;}  
 
void add(int u,int v,int z){e[t]=(edge){v,z,head[u]};head[u]=t++;} 
 
void dijkstra()  
{  
    memset(vis,0,sizeof(vis));  
    for(int i=1;i<=n;i++) dis[i]=INF;  
    dis[1]=0;q.push(make_pair(0,1));  
    while(!q.empty())
    {  
        int u=q.top().second;q.pop();  
        if(vis[u]) continue;vis[u]=1;  
        for(int i=head[u];i!=-1;i=e[i].nex){
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].val) dis[v]=dis[u]+e[i].val,q.push(make_pair(dis[v],v));  
        }
    }
}  
 
void work()
{
    sort(a+1,a+n+1,cmpx);
    for(int i=1;i<n;i++) add(a[i].id,a[i+1].id,a[i+1].x-a[i].x),add(a[i+1].id,a[i].id,a[i+1].x-a[i].x);
    sort(a+1,a+n+1,cmpy);  
    for (int i=1;i<n;i++) add(a[i].id,a[i+1].id,a[i+1].y-a[i].y),add(a[i+1].id,a[i].id,a[i+1].y-a[i].y);  
    dijkstra();  
    printf("%lld\n",dis[n]);  
}
 
void init()
{
    t=1;memset(head,-1,sizeof(head));
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y),a[i].id=i;
}
 
int main()  
{  
    init();
    work();
    return 0;  
}  
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值