📂题解
🔖图论
2023-03-01 15:39阅读: 20评论: 0推荐: 0

Gym100959I-Robots题解

题意:平面直角坐标系上有 n 个机器人,每个机器人有一个上下左右之一的方向,初始所有机器人静止。在第 0 秒,你让第一个机器人开始朝它的方向移动,速度为每秒一个单位。如果一个移动的机器人碰到了一个静止的机器人,该静止机器人也开始朝它的方向移动。需要注意的是,一个移动的机器人无论是否碰到其他机器人,移动的方向和速度永远不会改变。求 T 秒后的状态。

由于一旦开始移动,后面的状态都是很简单的,所以只需要求出每个机器人从什么时候开始移动即可。考虑如下建图:若机器人 ix 秒后会碰到机器人 j,则连一条 ixj 的边。则每个机器人开始移动的时间即为从 1 走到该点的最短路。

此时只剩一个问题:建图是 n2 的。我们可以发现,当一个向上的机器人 i 撞到了一个同样向上的机器人 j 时,ij 便没有本质区别了,只需要保留一个。此时有两种处理方式:舍弃 i 和舍弃 j。容易证明此时建图的边数变为了 O(n) 条。

舍弃 i 的实现:

By cxm1024

#include<bits/stdc++.h>
using namespace std;
#define int long long
struct node {
	int x,y;
	char d;
} a[100010];
map<int,set<pair<int,int> > > mx,my;
vector<pair<int,int> > e[100010];
int ans[100010];
bool done[100010];
void dijkstra(int s) {
	struct node2 {
		int u,w;
		bool operator<(const node2 &o)const {
			return w>o.w;
		}
	};
	priority_queue<node2> q;
	q.push({s,0});
	while(!q.empty()) {
		auto [u,w]=q.top();q.pop();
		if(done[u]) continue;
		done[u]=1,ans[u]=w;
		for(auto v:e[u])
			if(!done[v.first])
				q.push({v.first,w+v.second});
	}
}
signed main() {
	int n,t;
	cin>>n>>t;
	for(int i=1;i<=n;i++) {
		cin>>a[i].x>>a[i].y>>a[i].d;
		mx[a[i].x].insert({a[i].y,i});
		my[a[i].y].insert({a[i].x,i});
	}
	for(int i=1;i<=n;i++) {
		if(a[i].d=='U') {
			auto &s=mx[a[i].x];
			for(auto tmp=s.find({a[i].y,i});tmp!=s.end();tmp++) {
				if((*tmp).second==i) continue;
				e[i].push_back({(*tmp).second,(*tmp).first-a[i].y});
				if(a[(*tmp).second].d=='U') break;
			}
		}
		else if(a[i].d=='D') {
			auto &s=mx[a[i].x];
			for(auto tmp=s.find({a[i].y,i});;) {
				if((*tmp).second!=i) {
					e[i].push_back({(*tmp).second,a[i].y-(*tmp).first});
					if(a[(*tmp).second].d=='D') break;
				}
				if(tmp==s.begin()) break;
				else tmp--;
			}
		}
		else if(a[i].d=='L') {
			auto &s=my[a[i].y];
			for(auto tmp=s.find({a[i].x,i});;) {
				if((*tmp).second!=i) {
					e[i].push_back({(*tmp).second,a[i].x-(*tmp).first});
					if(a[(*tmp).second].d=='L') break;
				}
				if(tmp==s.begin()) break;
				else tmp--;
			}
		}
		else {
			auto &s=my[a[i].y];
			for(auto tmp=s.find({a[i].x,i});tmp!=s.end();tmp++) {
				if((*tmp).second==i) continue;
				e[i].push_back({(*tmp).second,(*tmp).first-a[i].x});
				if(a[(*tmp).second].d=='R') break;
			}
		}
	}
	dijkstra(1);
	for(int i=1;i<=n;i++) {
		if(!done[i]||ans[i]>t) {
			cout<<a[i].x<<" "<<a[i].y<<endl;
			continue;
		}
		int len=t-ans[i];
		if(a[i].d=='U') a[i].y+=len;
		else if(a[i].d=='D') a[i].y-=len;
		else if(a[i].d=='L') a[i].x-=len;
		else a[i].x+=len;
		cout<<a[i].x<<" "<<a[i].y<<endl;
	}
	return 0;
}

舍弃 j 的实现:

By ainta

#include<stdio.h>
#include<algorithm>
#include<queue>
#define pli pair<long long,int>
using namespace std;
vector<int>E[101000], L[101000];
struct point{
    int x, y, num, dir;
    bool operator <(const point &p)const{
        return x!=p.x?x<p.x:y<p.y;
    }
}w[101000], ori[101000];
int n;
long long T, D[101000];
priority_queue<pli>PQ;
void Ins(int a, long long d){
    if(D[a]<=d)return;
    D[a]=d;
    PQ.push(pli(-d,a));
}
void Dijk(){
    int i, a;
    for(i=1;i<=n;i++)D[i] = 2e18;
    Ins(1,0);
    pli tp;
    while(1){
        while(!PQ.empty()){
            tp = PQ.top();
            if(D[tp.second] == -tp.first)break;
            PQ.pop();
        }
        if(PQ.empty())break;
        tp = PQ.top();
        a = tp.second;
        PQ.pop();
        for(i=0;i<E[a].size();i++){
            Ins(E[a][i],D[a]+L[a][i]);
        }
    }
}
void Add(int a, int b, int c){
    E[a].push_back(b);
    L[a].push_back(c);
}
int main(){
    int i, j, e, pv, y;
    char pp[3];
    scanf("%d%lld",&n,&T);
    for(i=1;i<=n;i++){
        scanf("%d%d",&w[i].x,&w[i].y);
        scanf("%s",pp);
        if(pp[0]=='U')w[i].dir = 1;
        if(pp[0]=='D')w[i].dir = 2;
        if(pp[0]=='R')w[i].dir = 3;
        if(pp[0]=='L')w[i].dir = 4;
        w[i].num = i;
        ori[i] = w[i];
    }
    sort(w+1,w+n+1);
    for(i=1;i<=n;i++){
        for(j=i;j<=n;j++)if(w[j].x!=w[i].x)break;
        e=j-1;
        pv = 0;
        for(j=i;j<=e;j++){
            if(pv)Add(pv,w[j].num,w[j].y-y);
            if(w[j].dir == 1)pv = w[j].num, y = w[j].y;
        }
        pv = 0;
        for(j=e;j>=i;j--){
            if(pv)Add(pv,w[j].num,y-w[j].y);
            if(w[j].dir == 2)pv = w[j].num, y = w[j].y;
        }
        i=e;
    }
    for(i=1;i<=n;i++)swap(w[i].x,w[i].y);
    sort(w+1,w+n+1);
    for(i=1;i<=n;i++){
        for(j=i;j<=n;j++)if(w[j].x!=w[i].x)break;
        e=j-1;
        pv = 0;
        for(j=i;j<=e;j++){
            if(pv)Add(pv,w[j].num,w[j].y-y);
            if(w[j].dir == 3)pv = w[j].num, y = w[j].y;
        }
        pv = 0;
        for(j=e;j>=i;j--){
            if(pv)Add(pv,w[j].num,y-w[j].y);
            if(w[j].dir == 4)pv = w[j].num, y = w[j].y;
        }
        i=e;
    }
    Dijk();
    long long xx,yy;
    for(i=1;i<=n;i++){
        xx=ori[i].x,yy=ori[i].y;
        if(D[i]<=T){
            if(ori[i].dir==1)yy+=T-D[i];
            if(ori[i].dir==2)yy-=T-D[i];
            if(ori[i].dir==3)xx+=T-D[i];
            if(ori[i].dir==4)xx-=T-D[i];
        }
        printf("%lld %lld\n",xx,yy);
    }
}
posted @   曹轩鸣  阅读(20)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起