P神的SDFZ考试题 C题
探险
【问题描述】
探险家小 T 好高兴! X 国要举办一次溶洞探险比赛,获奖者将得到丰厚奖品
哦!小 T 虽然对奖品不感兴趣,但是这个大振名声的机会当然不能错过!
比赛即将开始,工作人员说明了这次比赛的规则:每个溶洞和其他某些溶洞
有暗道相连。两个溶洞之间可能有多条道路,也有可能没有,但没有一条暗道直
接从自己连到自己。参赛者需要统一从一个大溶洞出发,并再次回到这个大溶洞。
如果就这么点限制,那么问题就太简单了,可是举办方又提出了一个条件:
不能经过同一条暗道两次。这个条件让大家犯难了。这该怎么办呢?
到了大溶洞口后,小 T 愉悦地发现这个地方他曾经来过,他还记得有哪些
暗道,以及通过每条暗道的时间。小 T 现在向你求助,你能帮他算出至少要多
少时间才能回到大溶洞吗?(起点编号为 1)
【输入格式】
第一行两个数 n , m 表示溶洞的数量以及暗道的数量。
接下来 m 行,每行 4 个数 s 、 t 、 w 、 v,表示一个暗道连接的两个溶洞 s 、 t,
这条暗道正着走(s à t)的所需要的时间 w,倒着走(t à s)所需要的时间 v。
由于溶洞的相对位置不同,w 与 v 可能不同。
【输出格式】
输出一行一个数 t,表示最少所需要的时间。
【样例输入】
3 3
1 2 2 1
2 3 4 5
3 1 2 3
【样例输出】
8
这又是一道bzoj的权限题
首先这个题可以打一个暴力的写法:
枚举从一号节点出发第一个走的溶洞,再强行把那条边断开,然后求那个溶洞到一号节点的最短路相加
好像这样是能过的样子
正解有一个极其鬼畜的建图根本看不懂(其实就算看懂了以后也想不出来)
于是P神还有一个一句话嘴巴AC的正解
在spfa的时候维护到一个点的最短路和次短路并且保证最短路和次短路的第一条边不一样,
然后再枚举和1相连的边回去即可
(优先考虑最短路+这条边,如果发现最短路的第一条边和这条边相同,就用次长边+这条边(次长边和最长边的第一条边不同)
Orz Orz跪地膜啊,简单粗暴
但不过这个东西的if打得是真的操蛋啊
其实理清楚了,也就是想写数学大题的分类讨论吧
附上巨丑代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1000050;
const int Inf=20010411;
int gi(){
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
int cnt=1,n,m,head[N],to[N],nxt[N],c[N],in[N],vis[N],ans=Inf,vis2[N];
int W[N];
struct Data{
int first,second,ffrom,sfrom;
}dis[N];
struct data{
int x,fa,from;
}q[N*2];
void lnk(int x,int y,int v,int z){
to[++cnt]=y,c[cnt]=v,nxt[cnt]=head[x],head[x]=cnt;
to[++cnt]=x,c[cnt]=z,nxt[cnt]=head[y],head[y]=cnt;
}
void spfa(){
int t=0,sum=1;q[0].x=1;dis[1].first=dis[1].second=0;
while(t<sum){
data now=q[t++];
for(int i=head[now.x];i;i=nxt[i]){
if(i!=(now.fa^1)||now.fa==0){
int y=to[i],flag=0;
/*//我们不妨定义xf,xs,yf,ys表示这四条路径长度的鬼畜关系
//先确定长度后再转移
//首先我们知道 xf<xs和yf<ys;
//下面把所有情况列举下来:
//1.xf<yf<xs<ys
//2.xf<yf<ys<xs
//3.xf<xs<yf<ys
//4.xf<xs<yf<ys
//-------------------
//5.yf<xf<xs<ys
//6.yf<xf<ys<xs
//7.yf<ys<xf<xs*/
if(now.x!=1){
if(dis[now.x].first+c[i]<dis[y].first){
//当前更新的路比y的最短路还要短,那么y的最短路一定会被更新,次短路可能会更新
if(dis[y].first<dis[now.x].second+c[i]){
//xf<yf<(xs,ys未知)
if(dis[y].ffrom!=dis[now.x].ffrom){
//xf和yf的第一条边不同,又已知yf和ys的第一条边不会一样
//那么xs不需要考虑
//转移:ys=yf,yf=xf
dis[y].second=dis[y].first;dis[y].sfrom=dis[y].ffrom;
dis[y].first=dis[now.x].first+c[i];dis[y].ffrom=dis[now.x].ffrom;
flag=1;
}
else{
//xf和yf的第一条边相同,yf必定要变成xf的,我们要考虑xs怎么变
//1.xf<yf<ys<xs,那么ys保持不变
if(dis[y].second<dis[now.x].second){
dis[y].first=dis[now.x].first+c[i];
dis[y].ffrom=dis[now.x].ffrom;
flag=1;
}
//2.xf<yf<xs<ys
else{
//如果yf和xs的第一条边不同
//yf=xf,ys=xs;
if(dis[y].ffrom!=dis[now.x].sfrom){
dis[y].first=dis[now.x].first+c[i];
dis[y].ffrom=dis[now.x].ffrom;
dis[y].second=dis[now.x].second+c[i];
dis[y].sfrom=dis[now.x].sfrom;
flag=1;
}
}
}
}
else{//xf<xs<yf<ys,这么好打的一个我竟然忘记了
//这个最理想了直接yf=xf,ys=xs
dis[y].first=dis[now.x].first+c[i];
dis[y].ffrom=dis[now.x].ffrom;
dis[y].second=dis[now.x].second+c[i];
dis[y].sfrom=dis[now.x].sfrom;
}
}
else {//现在是yf<xf
//yf<(xf<xs,ys)未知,那么yf是不能被更新了吧
//1.yf<xf<ys<xs;
if(dis[y].second<dis[now.x].second+c[i]&&dis[y].second>dis[now.x].first+c[i]){
if(dis[y].ffrom!=dis[now.x].ffrom){//yf和xf的第一条边没有冲突,ys=xf;
dis[y].second=dis[now.x].first+c[i];
dis[y].sfrom=dis[now.x].ffrom;
flag=1;
}
}
//2.yf<ys<xf<xs 根本不需要更新
//3.yf<xf<xs<ys;
else if(dis[y].second>dis[now.x].second+c[i]){
if(dis[y].ffrom!=dis[now.x].ffrom){//优先考虑xf来更新
dis[y].second=dis[now.x].first+c[i];
dis[y].sfrom=dis[now.x].ffrom;
flag=1;
}
else if(dis[y].ffrom!=dis[now.x].sfrom){
dis[y].second=dis[now.x].second+c[i];
dis[y].sfrom=dis[now.x].sfrom;
flag=1;
}
}
}
}
if(flag||now.x==1){
q[sum++]=(data){y,i};
}
}
}
}
}
int main(){
freopen("exp.in","r",stdin);
freopen("exp.out","w",stdout);
n=gi(),m=gi();
for(int i=1;i<=m;i++){
int x=gi(),y=gi(),v=gi(),z=gi();
lnk(x,y,v,z);
}
for(int i=2;i<=n;i++) dis[i].first=dis[i].second=Inf;
for(int i=head[1];i;i=nxt[i]){
if(dis[to[i]].first==Inf){
dis[to[i]].first=c[i];
dis[to[i]].ffrom=i;
}
else{
if(dis[to[i]].first>c[i]){
dis[to[i]].second=dis[to[i]].first;
dis[to[i]].sfrom=dis[to[i]].ffrom;
dis[to[i]].first=c[i];
dis[to[i]].ffrom=i;
}
else{
if(dis[i].second>c[i]){
dis[to[i]].second=c[i];
dis[to[i]].sfrom=i;
}
}
}
}
spfa();
for(int i=head[1];i;i=nxt[i]){
int y=to[i];
if(dis[y].ffrom!=i) ans=min(ans,dis[y].first+c[i^1]);
else ans=min(ans,dis[y].second+c[i^1]);
}
printf("%d",ans);
}
P神的SDFZ考试题 C题的更多相关文章
- 刷题向》关于一道尺取法的神题目(BZOJ4653)(HARD-)(BZOJ 30题纪念)
不得不说,这也许会是一道长期在我的博客里作为“HARD”难度存在的题 这道题能很好的考验选手的思考能力,但本蒟蒻最后还是听了省队爷讲了之后才会...(默默面壁) 题目里,说对于每一个点,是用当前选出的 ...
- csu 10月 月赛 H 题 A Very Hard Problem
Description CX老湿经常被人黑,被黑得多了,自己也就麻木了.于是经常听到有人黑他,他都会深情地说一句:禽兽啊! 一天CX老湿突发奇想,给大家出了一个难题,并且声称谁能够准确地回答出问题才能 ...
- [BJOI2019]勘破神机
[BJOI2019]勘破神机 推式子好题 m=2,斐波那契数列,$f_{n+1}$项 不妨$++l,++r$,直接求$f_n$ 求$\sum C(f_n,k)$,下降幂转化成阶乘幂,这样都是多项式了, ...
- C++笔试易错题集(持续更新)
1.如下代码输出结果是什么? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include<stdio.h> char *myString() { ...
- 【BZOJ4916】神犇和蒟蒻 解题报告
[BZOJ4916]神犇和蒟蒻 Description 很久很久以前,有一群神犇叫sk和ypl和ssr和hjh和hgr和gjs和yay和xj和zwl和dcx和lyy和dtz和hy和xfz和myh和yw ...
- Python基础数据类型题
Python基础数据类型 题考试时间:三个小时 满分100分(80分以上包含80分及格)1,简述变量命名规范(3分) 1.必须是字母,数字,下划线的任意组合. 2.不能是数字开头 3.不能是pytho ...
- Codeforces数据结构(水题)小结
最近在使用codeblock,所以就先刷一些水题上上手 使用codeblock遇到的问题 1.无法进行编译-------从setting中的编译器设置中配置编译器 2.建立cpp后无法调试------ ...
- [日常] NOIP前集训日记
写点流水账放松身心... 10.8 前一天考完NHEEE的一调考试终于可以开始集训了Orz (然后上来考试就迟到5min, GG) T1维护队列瞎贪心, 过了大样例交上去一点也不稳...T出翔只拿了5 ...
- PKUSC2016
day x(x<0) 外出培训倒数第二天晚上发烧了....逃过了第二天早上的考试,orz 抢到rank 1 的commonc神犇!! day 0 下午到了北大,发了两张50元饭卡.这是第三次来北 ...
随机推荐
- 熵(Entropy),交叉熵(Cross-Entropy),KL-松散度(KL Divergence)
1.介绍: 当我们开发一个分类模型的时候,我们的目标是把输入映射到预测的概率上,当我们训练模型的时候就不停地调整参数使得我们预测出来的概率和真是的概率更加接近. 这篇文章我们关注在我们的模型假设这些类 ...
- dataset的使用和图片延时加载的实现
首先,先介绍一下关于javascript中dataset属性..html5中可以使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放.下面是元素应用data属性的一个例子:~~~~~~~~ ...
- HDU 1754 线段树 单点跟新 HDU 1166 敌兵布阵 线段树 区间求和
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 算法训练 K好数
算法训练 K好数 时间限制:1.0s 内存限制:256.0MB 问题描述 如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数.求L位K进制数中K好数 ...
- yii2 邮件发送
修改配置文件mail-local.php 'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', 'useFileTransport' =&g ...
- 日志模块---logging
作用 在程序的运行过程中,会遇到很多需要打印的中间信息,通过使用logging模块可以详细的输出信息,不同于print()函数的单一功能. 应用场景 对于软件程序的运行过程中输出中间信息,如账单信息, ...
- javaScript 验证码 倒计时60秒
<input type="button" id="btn" value="免费获取验证码" /> <script type ...
- TCP的十一种状态与三次握手分析(有图)
我们知道TCP是面向连接的,我们只知道有连接断开,其实内部还有一些比较复杂的状态.去了解各个状态之间的切换有助于我们更加深入的了解TCP.下面我们就来分析各个状态. 1.如下图示(图源百度)图中显示出 ...
- poj Minimum( CutStoer Wagner算法)
Minimum Cut 题目: 给出一张图.要求你删除最小割权和图. 算法分析: //////////////////// 转载 --- ylfdrib ///////////////// ...
- EGOCache缓存框架具体解说
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...