题解:ABC320D - Relative Position
·题目
链接:Atcoder。
链接:洛谷。
·难度
算法难度:B。
思维难度:A。
调码难度:A。
综合评价:普及/提高-。
·算法
宽度优先搜索。
·思路
先定义一个结构体,存储x、y坐标,重载加法运算为{a.x+b.x,a.y+b.y}。每一套关系都看做一条有权值的边,当然权值是“坐标”类型的,权值就是基准点(第一个数)的x、y分别加上多少(第3、4个数)能变为目标点(第二个数),当然反过来也要连接,只不过权值参数要变为“0-原来的数”。然后用bfs跑,入口就是1号小人在原点,每次遍历到另一个小人时就能求出该小人相应坐标,最后输出每个人的坐标,特判没有遍历到的点即可。
·代价
O(n+m),bfs占大头。
·细节
边的类型:vector<pair<Place,int>>edge[M]={};
队列的类型:pair<Place,int>q[N]={};
判段是否入队的数组的类型:bool pc[N]={};
·代码
#include<bits/stdc++.h>
#define M 220000
#define N 220000
using namespace std;
struct Place{
long long x,y;
Place operator+(Place ot){
return{x+ot.x,y+ot.y};
}
};
vector<pair<Place,int>>edge[M]={};
//边
pair<Place,int>q[N]={};
//队列
long long ansx[N]={},ansy[N]={},m=0,n=0;
//答案x坐标、答案y坐标、关系个数、人的个数
bool pc[N]={};
//判断是否在bfs中已经入队
int main(){
scanf("%lld%lld",&n,&m);
for(long long i=1;i<=m;i++){
long long a=0,b=0;
Place p={};
scanf("%lld%lld%lld%lld",&a,&b,&p.x,&p.y);
edge[a].push_back({p,b});
Place q={-p.x,-p.y};
edge[b].push_back({q,a});
}
//输入、连边
long long front=1,rear=1;
q[1]={{0,0},1};
pc[1]=true;
//原点入队
while(front<=rear){
for(pair<Place,int>i:edge[q[front].second]){
if(pc[i.second]==false){
rear++;
q[rear]={q[front].first+i.first,i.second};
//新元素入队
ansx[i.second]=q[rear].first.x;
ansy[i.second]=q[rear].first.y;
//答案更新
pc[i.second]=true;
//标记入队
}
}
front++;
//队首出队
}
//bfs
for(long long i=1;i<=n;i++){
if(pc[i]==true){
printf("%lld %lld\n",ansx[i],ansy[i]);
}else{
printf("undecidable\n");
}
//有入过队的输出坐标,否则输出“不知道”
}
//输出答案
return 0;
}
·注意
反着连边的时候权值取反。