题意描述

Around the world

在一个圆上有 \(n\) 点,其中有 \(m\) 条双向边连接它们,每条双向边连接两点总是沿着圆的最小弧连接。

求从 \(1\) 号点出发并回到 \(1\) 号点的一条路径,在满足并非原路返回的情况下满足经过路线数量最小。

如果不存在这样的路径输出 \(-1\)。

算法分析

本来好好的一道 BFS 被我想的辣么复杂...。

如果是单向边就是一遍 BFS 的事,但是这里是双向边又不能原路返回...。

首先考虑特殊建边:

对于 \(edge(u,v)\),求出两者的距离 \(w=dis(u,v)\)。

如果 \(u\to v\) 是顺时针走建立 \(edge(u,v,w),edge(v,u,-w)\)。

否则建立 \(edge(v,u,w),edge(u,v,-w)\)。

然后 BFS 的同时计算走过的边权之和,只要到达 \(1\) 号点时边权之和 \(\neq 0\) 即可。

判重本来是用 \(bool\) 判的,然后喜得 MLE,所以乖乖用 set 了。

当然为了减小常数,dalao 都是直接用 Hash。(蒟蒻我懒...)

没了。

代码实现

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<set>
#define N 5010
#define M 25010
using namespace std; int n,m,a[N],head[N],cnt=0;
struct Edge{
int nxt,to,val;
}ed[M<<1];
struct node{
int u,dis,step;
};
queue<node>q;
set<pair<int,int> >s; int read(){
int x=0,f=1;char c=getchar();
while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
return x*f;
} int get_dis(int u,int v){
int w=min(abs(u-v),360-abs(u-v));
if((u+w)%360==v) return w;
return -w;
} void add(int u,int v,int w){
ed[++cnt]=(Edge){head[u],v,w},head[u]=cnt;
ed[++cnt]=(Edge){head[v],u,-w},head[v]=cnt;
return;
} int bfs(){
q.push((node){1,0,0});
while(!q.empty()){
node now=q.front();q.pop();
int u=now.u,dis=now.dis,step=now.step;
s.insert(make_pair(u,dis));
for(int i=head[u];i;i=ed[i].nxt){
int v=ed[i].to,w=ed[i].val;
if(v==1 && dis+w) return step+1;
if(s.find(make_pair(v,dis+w))!=s.end()) continue;
//set 提供 find 这个成员函数,如果其中没有这个值将返回 s.end()。
q.push((node){v,dis+w,step+1});
}
}
return -1;
} int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=m;i++){//特殊建边。
int u=read(),v=read();
int w=get_dis(a[u],a[v]);
if(w>0) add(u,v,w);
else add(v,u,-w);
}
printf("%d\n",bfs());
return 0;
}

完结撒花

POJ2432 Around the world的更多相关文章

随机推荐

  1. sed: -e expression #1, char 23: unknown option to `s'

    语言:bash why? / 作为sed的分隔符,和需要操作的内容有冲突 way? 替换 / 分隔符为 # 或者其他分隔符

  2. unittest培训后总结记录

    今天在给同学们上了自动化测试单元框架unittest之后,突发奇想,要总结下自己今天上的课程内容.于是有了下面的一幕: 首先,今天上课的目标是要学会关于unittest框架的基本使用及断言.批量执行. ...

  3. Linux系统编程 —时序竞态

    时序竞态 什么是时序竞态?将同一个程序执行两次,正常情况下,前后两次执行得到的结果应该是一样的.但由于系统资源竞争的原因,前后两次执行的结果有可能得到不一样的结果,这个现象就是时序竞态. pause函 ...

  4. P5091 【模板】扩展欧拉定理

    题目链接 昨天考试考到了欧拉公式,结果发现自己不会,就来恶补一下. 欧拉公式 \(a^b \bmod p = a^{b}\) \(b < \varphi(p)\) \(a^b \bmod p = ...

  5. Linux为STDOUT的关键字设置颜色

    echo "颜色测试aaa实测" | perl -pe 's/(aaa|实|测)/\e[1;31m$1\e[0m/g'

  6. vue使用vueCropper裁剪功能,代码复制直接使用

    //先安装包 npm install vue-cropper --save-dev <template> <div id="merchantInformation" ...

  7. NOI 2012 【迷失游乐园】

    这道题,额,反正我是刚了2天,然后就萎了......(是不是觉得我很菜) 题目描述: 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩. 进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐 ...

  8. C# 主界面的扁平化

    如果需要查看更多文章,请微信搜索公众号 csharp编程大全,需要进C#交流群群请加微信z438679770,备注进群, 我邀请你进群! ! ! --------------------------- ...

  9. ansible-任务控制tags

    1. ansible-任务控制tags介绍        如果你有一个大型的剧本,那么只能运行它的特定部分而不是在剧本中运行所有内容可能会很有用.因此,Ansible支持"tags:&quo ...

  10. Java 移位运算、符号位扩展

    类型取值范围 short 是1字节,即8位.而且 Java 中只有有符号数,所以最大值 0111,1111=2^7-1. 同时计算机中以补码形式存负数,所以可以多表示一个数,则最小值 1000,000 ...