ICPCCamp2016day8 I Robots 【最短路】

题意:有n个机器人在二维平面内,第i个机器人有一个初始坐标(xi,yi)和一个行走方向,用‘U’,‘D’,‘L’,‘R’表示上下左右;

每个机器人被其他机器人碰到才能动,刚开始只有第一个机器人能动;问T时间后每个机器人的坐标。

数据范围:
1<=n<=100000
0<=T<=10^18
0<=xi,yi<=10^9
分析:
由于每个点都有一个方向,将每个点与自己方向上的所有点连边,可以发先,题目转换成求1到其他所有点的最短时间,
最后用T-dis[i]得到剩余时间。xi,yi太大,所以离散化,然后把每个x上,每个y上的点存下来排个序,排完序后就是建
边了,但是直接将每个点与自己方向上的所有点连边有点炸,比如点全在一个x或y上且方向一样,这样就有n^2条边,
所以我们建边的时候可以将每个点与自己(a点)方向上下一个同向的点(b点)之间的点连边,因为b点与a点同向,
a就没有必要向b以后的点连边。最后跑遍dijkstra。

代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 100010
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
struct edge {
    int v,w,next;
}e[Mm];
int tot,head[Mn];
void addedge(int u,int v,int w) {
    e[tot].v=v;
    e[tot].w=w;
    e[tot].next=head[u];
    head[u]=tot++;
}
struct point {
    int x,y;
    char c;
    point(){}
    point(int x,int y,char c):x(x),y(y),c(c){}
}po[Mn];
struct vtv {
    int a,id;
    vtv(){}
    vtv(int a,int id):a(a),id(id){}
    bool operator<(const vtv &x) const {
        return x.a>a;
    }
};
struct node {
    int v;
    ll cost;
    node(int v,ll cost) : v(v),cost(cost) {};
    bool operator <(const node x) const {
        return cost>x.cost;
    }
};
int vis[Mn],n;
ll dis[Mn];
void dijstra(int st) {
    priority_queue<node> q;
    for(int i=1;i<=n;i++) dis[i]=10e17;
    CLR(vis,0);
    dis[st]=0;
    q.push(node(st,0));
    while(!q.empty()) {
        node tmp=q.top();
        q.pop();
        int u=tmp.v;
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u]; i!=-1; i=e[i].next) {
            int v=e[i].v;
            ll cost=e[i].w;
            if(!vis[v]&&dis[v]>dis[u]+cost) {
                dis[v]=dis[u]+cost;
                q.push(node(v,dis[v]));
            }
        }
    }
}
void init() {
    tot=0;
    CLR(head,-1);
}
int h[Mn],w[Mn];
vector<vtv> vh[Mn],vw[Mn];
int main() {
    ll T;char s[2];
    init();
    scanf("%d%lld",&n,&T);
    int hcnt=0,wcnt=0;
    for(int i=1;i<=n;i++) {
        int x,y;
        scanf("%d%d%s",&x,&y,s);
        h[hcnt++]=x;
        w[wcnt++]=y;
        po[i]=point(x,y,s[0]);
    }
    sort(h,h+hcnt);
    sort(w,w+wcnt);
    int h_cnt=unique(h,h+hcnt)-h;
    int w_cnt=unique(w,w+wcnt)-w;
    for(int i=1;i<=n;i++) {
        int posx=lower_bound(h,h+h_cnt,po[i].x)-h;
        int posy=lower_bound(w,w+w_cnt,po[i].y)-w;
        vh[posx].push_back(vtv(posy,i));
        vw[posy].push_back(vtv(posx,i));
    }
    int u,v;
    for(int i=0;i<h_cnt;i++) {
        u=-1;
        sort(vh[i].begin(),vh[i].end());
        for(int j=0;j<vh[i].size();j++) {
            int id=vh[i][j].id;
            if(u!=-1) addedge(u,id,po[id].y-po[u].y);
            if(po[id].c=='U') u=id;
        }
        v=-1;
        for(int j=vh[i].size()-1;j>=0;j--) {
            int id=vh[i][j].id;
            if(v!=-1) addedge(v,id,po[v].y-po[id].y);
            if(po[id].c=='D') v=id;
        }
    }
    for(int i=0;i<w_cnt;i++) {
        u=-1;
        sort(vw[i].begin(),vw[i].end());
        for(int j=0;j<vw[i].size();j++) {
            int id=vw[i][j].id;
            if(u!=-1) addedge(u,id,po[id].x-po[u].x);
            if(po[id].c=='R') u=id;
        }
        v=-1;
        for(int j=vw[i].size()-1;j>=0;j--) {
            int id=vw[i][j].id;
            if(v!=-1) addedge(v,id,po[v].x-po[id].x);
            if(po[id].c=='L') v=id;
        }
    }
    dijstra(1);
    for(int i=1;i<=n;i++) {
        ll ans=max(T-dis[i],0LL);
        ll x=po[i].x,y=po[i].y;
        if(po[i].c=='U') y+=ans;
        if(po[i].c=='D') y-=ans;
        if(po[i].c=='L') x-=ans;
        if(po[i].c=='R') x+=ans;
        printf("%lld %lld\n",x,y);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值