T2 洞穴zaw

【问题描述】

在 Byte 山的山脚下有一个洞穴入口. 这个洞穴由复杂的洞室经过隧道连接构成. 洞穴的入口是 1 号点.两个洞室要么就通过隧道连接起来,要么就经过若干隧道间接的相连. 现在决定组织办一个'King's of Byteotia Cup' 比赛. 参赛者的目标就是任意选择一条路径进入洞穴并尽快出来即可. 一条路径必须经过除了 1 之外还至少要经过其他一个洞室.一条路径中一个洞不能重复经过(除了 1 以外),类似的一条隧道也不能重复经过.

一个著名的洞穴探险家 Byteala 正准备参加这个比赛. Byteala 已经训练了数月而且他已获得了洞穴系统的一套详细资料. 对于每条隧道他都详细计算了从两个方向经过所需要的时间. 经过一个洞室的时间很短可以忽略不记. 现在Byteala 向计算一条符合条件的最优路径.

【输入格式】

第一行有两个数 n 和 m (3 <= n <= 5000, 3 <= m <= 10000) 分别表示洞室的数目以及连接他们的隧道的数目. 洞室从 1 到 n 编号. “前面洞室”的编号为 1.接下来 m 行描述了所有的隧道. 每行四个整数 a,b,c,d 表示从洞室 a 到洞室 b 需要 c 分钟的时间,而从洞室 b 到洞室 a 需要 d 分钟的时间, 1 <= a,b <= n, a <> b, 1 <=c,d <= 10000. 你可以假设符合要求的路径肯定存在.

【输出格式】

输出一行,最少需要多少时间完成比赛.

【样例输入】

3 3

1 2 4 3

2 3 4 2

1 3 1 1

【样例输出】

6

【说明】 

经过 1,2,3,1

Solution

来源:POI2004,Bzoj2069

①O(n^2logn)

从1点出发枚举会走到哪条边哪到哪个点,将这条边回边标为不可选,从那个点跑向1的最短路即可.

因为有些奇奇怪怪的剪枝,它会跑的非常快(0.08s即可,与正解差不了多少).

剪枝:

  1. 普通单源单汇的最短路剪枝,Dijskra算法,当前更新的最小点为汇点可直接输出
  2. 枚举的那条边>=ans直接不枚举
  3. 当前最小点+W[i](枚举的那条边)>=ans可以退出
  4. 到达的点>=ans可以不入队

②%DJ两遍最短路 nlogn

一条边相当与四条边,为什么呢?双向×走法(直+倒)

edge u→v w[1]=w1(直) w[2]=w2(倒)

edge v→u w[1]=w2(直) w[2]=w1(倒)

我们拿每条边w[1](标记v→w不能)从1跑最短路,第二遍用w[2]跑,这样是从1倒着走回到其他点,相当与从其它点走过来.

统计一下每个点两次答案之和即可.

对于从一出发的边标记颜色,到达的点的最短距离来自哪条边为哪个

最后统计答案,d[i](正)→d1[i](负)两点颜色不同.注意,与一号点相连的点可正反,因为一号点可走过多次。

Code

// <zaw.cpp> - Thu Oct  6 08:17:54 2016
// This file is made by YJinpeng,created by XuYike's black technology automatically.
// Copyright (C) 2016 ChangJun High School, Inc.
// I don't know what this program is.

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#define INF 1e9
#define IN inline
#define RG register
using namespace std;
typedef long long LL;
inline int gi() {register int w=0,q=0;register char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();if(ch=='-')q=1,ch=getchar();while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar();return q?-w:w;
}
const int N=5010,M=N<<2;
int n,m,t,ans;int d[N],fr[N];int to[M],ne[M],W[M];bool u[N];
struct node{int s,p;bool operator<(node a)const{return s>a.s;}
};
priority_queue<node>q;
IN void link(RG int u,RG int v,RG int w){to[++t]=v;ne[t]=fr[u];fr[u]=t;W[t]=w;//if(u==1)cout<<v<<endl;this
}
void read(){n=gi(),m=gi();while(m--){int u=gi(),v=gi(),w=gi(),w1=gi();link(u,v,w);link(v,u,w1);}
}
IN int Dij(RG int begin,RG int end,int w){for(int i=1;i<=n;i++)d[i]=INF;q.push((node){d[begin]=0,begin});memset(u,0,sizeof(u));while(!q.empty()){while(u[q.top().p]&&!q.empty())q.pop();if(q.empty())break;int x=q.top().p;q.pop();u[x]=1;if(w+d[x]>=ans)break;//thisif(x==end)return d[1];for(int o=fr[x],y;y=to[o],o;o=ne[o])if(d[x]+W[o]<d[y]){d[y]=d[x]+W[o];if(d[y]>=ans)continue;//this
                q.push((node){d[y],y});}}return d[1];
}
void Work(){read();ans=INF;for(int i=fr[1],w;i;i=ne[i]){if(W[i]>=ans)continue;//thisif(i&1)w=W[i+1],W[i+1]=INF;else w=W[i-1],W[i-1]=INF;ans=min(ans,W[i]+Dij(to[i],1,W[i]));if(i&1)W[i+1]=w;else W[i-1]=w;}printf("%d",ans);
}
int main()
{freopen("zaw.in","r",stdin);freopen("zaw.out","w",stdout);Work();return 0;
}

View Code

②dj's code

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#define in long long
using namespace std;
in getint(){in res=0,f=1;char c=getchar();while(c!='-' &&(c<'0' || c>'9'))c=getchar();if(c=='-'){f=-1;c=getchar();}while(c>='0' && c<='9'){res=res*10+c-'0';c=getchar();}return res*f;
}
struct lnode{int data,v,rev;bool g;lnode *next;
}*a[100001];
int n,m,k,top=1,tail=1,ans=999999999;
int d[100001][2],col[100001]={0},c[100001]={0};
int q[100001];
bool instack[100001]={0};
void spfa(int i){int x=q[i];lnode *p=a[x];while(p){if(d[p->data][0]>d[x][0]+p->v){if(instack[p->data]==false){instack[p->data]=true;d[p->data][0]=d[x][0]+p->v;col[p->data]=col[x];q[top++]=p->data;if(top>100000)top=1;}else{d[p->data][0]=d[x][0]+p->v;col[p->data]=col[x];}}p=p->next;}
}
void spfb(int i) {int x=q[i]; lnode *p=a[x]; while(p) { if(d[p->data][1]>d[x][1]+p->rev) { if(instack[p->data]==false) { instack[p->data]=true; d[p->data][1]=d[x][1]+p->rev; c[p->data]=c[x]; q[top++]=p->data;if(top>100000)top=1; }else { d[p->data][1]=d[x][1]+p->rev; c[p->data]=c[x]; } if(c[p->data]!=col[p->data])ans=min(ans,d[p->data][0]+d[p->data][1]); } else if(col[p->data]!=0 && c[x]!=col[p->data]) ans=min(ans,d[p->data][0]+d[x][1]+p->rev); p=p->next; }
}
int main()
{freopen("zaw.in","r",stdin);freopen("zaw.out","w",stdout);n=getint();m=getint();for(int i=1;i<=n;++i)a[i]=NULL,d[i][0]=999999999,d[i][1]=999999999;for(int i=1;i<=m;++i){int x=getint(),y=getint(),z1=getint(),z2=getint();;lnode *p=new lnode;p->data=y;p->v=z1;p->rev=z2;p->next=a[x];a[x]=p;p=new lnode;p->data=x;p->v=z2;p->rev=z1;p->next=a[y];a[y]=p;}lnode *p=a[1];int now=0;instack[1]=true;d[1][0]=0;while(p){q[top++]=p->data;col[p->data]=++now;d[p->data][0]=p->v;instack[p->data]=true;p=p->next;}while(tail!=top){spfa(tail);instack[q[tail]]=false;tail++;if(tail>100000)tail=1;}for(int i=2;i<=n;++i)instack[i]=false;instack[1]=true;d[1][1]=0;p=a[1];top=1;tail=1;now=0;while(p){q[top++]=p->data;c[p->data]=++now;d[p->data][1]=p->rev;instack[p->data]=true;p=p->next;}while(tail!=top){spfb(tail);instack[q[tail]]=false;tail++;if(tail>100000)tail=1;}cout<<ans;return 0;
}

View Code

转载于:https://www.cnblogs.com/YJinpeng/p/5936154.html

【POI2004】【Bzoj2069】T2 洞穴 zaw相关推荐

  1. [BZOJ2069][POI2004]ZAW

    BZOJ2069 描述 在Byte山的山脚下有一个洞穴入口. 这个洞穴由复杂的洞室经过隧道连接构成. 洞穴的入口是一条笔直通向"前面洞口"的道路. 隧道互相都不交叉(他们只在洞室相 ...

  2. 【BZOJ2069】ZAW(POI2004)-最短路+二进制分组

    测试地址:ZAW 题目大意: 给定一张边是双向的图,一条边走不同的方向可能代价不同,代价都非负,求从点111出发,不经过重复的点或边的最小回路.n≤5000,m≤10000n\le 5000,m\le ...

  3. 2069: [POI2004]ZAW

    2069: [POI2004]ZAW 链接 题意: 给定一张带权图(边是双向的,但不同方向长度不同).求从1出发,至少经过除1外的一个点,再回到1的最短路.点和边不能重复经过. n≤5000,m≤10 ...

  4. 【刷题】BZOJ 2069 [POI2004]ZAW

    Description 在Byte山的山脚下有一个洞穴入口. 这个洞穴由复杂的洞室经过隧道连接构成. 洞穴的入口是一条笔直通向"前面洞口"的道路. 隧道互相都不交叉(他们只在洞室相 ...

  5. BZOJ 2069: [POI2004]ZAW(Dijkstra + 二进制拆分)

    题意 给定一个有 \(N\) 个点 \(M\) 条边的无向图, 每条无向边 最多只能经过一次 . 对于边 \((u, v)\) , 从 \(u\) 到 \(v\) 的代价为 \(a\) , 从 \(v ...

  6. bzoj 2096 [POI2004]ZAW——二进制枚举

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2069 可以把直接相连的点分成  从1点出的一部分  和  走向1点的一部分.多起点最短路就和 ...

  7. BZOJ.2069.[POI2004]ZAW(最短路Dijkstra 按位划分)

    题目链接 \(Description\) 给定一张带权图(边是双向的,但不同方向长度不同).求从1出发,至少经过除1外的一个点,再回到1的最短路.点和边不能重复经过. \(n\leq5000,m\le ...

  8. BZOJ 2069 POI2004 ZAW 堆优化Dijkstra

    题目大意:给定一张无向图,每条边从两个方向走各有一个权值,求从点1往出走至少一步之后回到点1且不经过一条边多次的最短路 显然我们需要从点1出发走到某个和点1相邻的点上,然后沿最短路走到另一个和点1相邻 ...

  9. [POI 2004]ZAW

    [POI 2004]ZAW Description 在 Byte 山的山脚下有一个洞穴入口. 这个洞穴由复杂的洞室经过隧道连接构成. 洞穴的入口是 1号点.两个洞室要么就通过隧道连接起来,要么就经过若 ...

最新文章

  1. PNAS:微生物组互作塑造宿主适应度
  2. 4行代码,让app自动化框架支持 webview 混合应用操作
  3. 网站路径及文件路径问题
  4. leetCode:twoSum 两数之和 【JAVA实现】
  5. 【LeetCode】13. Roman to Integer
  6. Linux常用Shell脚本珍藏
  7. Ubuntu下配置samba实现文件夹共享
  8. 体验一下Oracle 11g物理Active Data Guard实时查询(Real-time query)
  9. 拼图游戏C语言课设实验报告,C语言拼图游戏实验报告.doc
  10. 飞畅 8口RS-485集线器产品性能参数介绍
  11. python缩进块是什么_python中缩进是用来做什么的
  12. ADMM算法的应用: 降低SDP算法复杂度
  13. 2021 年“认证杯”数学中国数学建模网络挑战赛 B题
  14. 计算机里比较器原理,数值比较器,数值比较器的作用和原理是 - 电子发烧友网...
  15. tdk怎么设置_SEO优化建议:如何正确设置TDK
  16. 使用switchshow/supportshow命令确认Brocade交换机型号(转载)
  17. ABBYY FineReader:PDF转换、一键OCR、图片转文字等,OCR识别一遍帮你搞定。
  18. 蓝桥杯_大胖子走迷宫
  19. 怎样用css3设计出向上向下的小箭头
  20. 多元线性回归的缺陷_多元线性回归常见问题

热门文章

  1. 基于51单片机自动数字电压表PCF8591 TLC2543 TL548 proteus仿真汇编程序设计
  2. 腾讯区块链的三年与它的打法 |链捕手
  3. 百万数据进行查询与排序
  4. 弱电时间同步系统(卫星同步时钟)医院学校标准时钟系统建设的意义
  5. iKinds:我是如何一步步重构改造项目从单VC到多VC界面(上)
  6. Linux命令--lsof
  7. LINUX 下SQL server 安装、配置及对接ceph功能性能测试
  8. 降低屏幕亮度,减缓眼疲劳 (linux/windows/firefox/android)
  9. Nanopi r4s usb网卡设置方法(MT7601U Wireless Adapter)
  10. 小米路由器3无线网连接到服务器,192.168.31.1小米路由器手机登录设置方法