WOJ#4709 迷路

题目描述

dolls意外得到了一张藏宝图,于是他踏上了寻找宝藏的道路。在走了许多许多步,回到同一个位置以后,dolls确定自己迷路了。dolls十分生气,他觉得自己这么英明圣武的人就算迷路,也要迷路在最小的环上。于是他想知道从每个点出发最小的环有多长。藏宝图可以抽象成一个n个点m条边的,边权全为正的无向图,现在你需要求得经过每个点的最小环长是多少。

输入格式

第一行两个数n,m,表示点数和边数。下面m行每行三个整数u,v,l表示点u和点v之间有一条长度为l的无向边。

输出格式

输出n个数,表示经过每个点的最小环长,若没有则输出-1。

数据范围

n≤300,m≤40000

题解

  从i点出发的最短路会构成一棵以i为根的最短路树。易知,经过i点的最小环应该是由最短路上的路径加上一条非树边构成的。由此我们可以想出这样一个算法:对于每个点i,我们构建出以它为根的最短路树,枚举非树边,如果该边之两端点之LCA为i,则用i到两点之最短路之和加上该边边权尝试更新答案。这一部分的时间复杂度应为O(nmlogn)。注意到n只有300而m只有40000,故这个算法完全可行。

  注意一些细节:

  1、记得开long long。

  2、预先特判自环,重边只保留最小的两条。

  3、关于最短路算法的选用:经计算,在该数据范围下,Floyd比跑n遍dijkstra快得多。

  放上代码:

#include<bits/stdc++.h>
using namespace std;
#define N 310
#define M 100010
#define LL long long
#define INF 0x3f3f3f3f
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
int num=,f[N];
struct node{
int u,v,w,nxt;
}e[M<<];
void add(int u,int v,int w){e[++num]=(node){u,v,w,f[u]};f[u]=num;}
//build graph
LL ans[N],Mp[N][N],dis[N][N];
void floyd(int n){
for(int k=;k<=n;k++)
for(int i=;i<=n;i++)
for(int j=;j<=n;j++) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
//shortest path
int inq[M<<],Add[N];
vector<int> g[N];
void build(int u,int st){
for(int i=f[u];i;i=e[i].nxt){
int v=e[i].v,w=e[i].w;
if(dis[st][v]==dis[st][u]+w&&!Add[v]){
inq[i]=inq[i^]=;Add[v]=;g[u].pb(v);g[v].pb(u);build(v,st);
}
}
}
//build tree
int dep[N],faz[N],sze[N],son[N],Top[N];
void dfs1(int u,int fa,int d){
dep[u]=d;sze[u]=;faz[u]=fa;
for(int i=;i^g[u].size();i++){
int v=g[u][i];
if(v==fa) continue;
dfs1(v,u,d+);sze[u]+=sze[v];
if(!son[u]||sze[v]>sze[son[u]]) son[u]=v;
}
}
void dfs2(int u,int st){
Top[u]=st;
if(!son[u]) return;
dfs2(son[u],st);
for(int i=;i^g[u].size();i++){
int v=g[u][i];
if(v==faz[u]||v==son[u]) continue;
dfs2(v,v);
}
}
int LCA(int x,int y){
int xx=Top[x],yy=Top[y];
while(xx!=yy){
if(dep[xx]<dep[yy]){swap(xx,yy);swap(x,y);}
x=faz[xx];xx=Top[x];
}
if(dep[x]>dep[y]) return y;
return x;
}
//tree dissection
inline int read(){
int x=,f=;char ch;
for(ch=getchar();(ch<''||ch>'')&&ch!='-';ch=getchar());
if(ch=='-'){f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
}
//读优
int n,m;
void write(int i){
if(ans[i]^ans[]) printf("%lld ",ans[i]);
else printf("-1 ");
}
int main(){
int x,y,z,sum=;
n=read();m=read();
memset(Mp,0x3f,sizeof(Mp));
memset(ans,0x3f,sizeof(ans));
memset(dis,0x3f,sizeof(dis));
for(int i=;i<=m;i++){
x=read();y=read();z=read();
if(i<=n) dis[i][i]=;
if(x==y){ans[x]=min(ans[x],(LL)z);continue;}
if(Mp[x][y]<=z) continue;
sum++;add(x,y,z),add(y,x,z);LL tmp=dis[x][y];
dis[x][y]=dis[y][x]=min(tmp,(LL)z);
Mp[x][y]=Mp[y][x]=max(tmp,(LL)z);
}
floyd(n);
for(int i=;i<=n;i++){
memset(Add,,sizeof(Add));
memset(dep,,sizeof(dep));
memset(faz,,sizeof(faz));
memset(sze,,sizeof(sze));
memset(son,,sizeof(son));
memset(Top,,sizeof(Top));
memset(inq,,sizeof(inq));
for(int j=;j<=n;j++) g[j].clear();
build(i,i);dfs1(i,i,);dfs2(i,i);
for(int j=;j<=num;j+=){
int u=e[j].u,v=e[j].v,w=e[j].w;LL tmp=dis[i][u]+dis[i][v]+w;
if(inq[j]||ans[i]<=tmp||LCA(u,v)^i) continue;
ans[i]=tmp;
}
write(i);
}
return ;
}

  

WOJ#4709 迷路的更多相关文章

  1. WOJ -1204

    WOJ -1204 1 出现次数大于一半 那么就利用普通的堆栈的思想,如果删除两个不同的元素,原来的多数元素还是多数元素,所以采取按条件入栈的方法,如果和top元素相同则入栈,否则top--,此元素也 ...

  2. hdu - 4709 - Herding

    题意:给出N个点的坐标,从中取些点来组成一个多边形,求这个多边形的最小面积,组不成多边形的输出"Impossible"(测试组数 T <= 25, 1 <= N < ...

  3. BZOJ 1297: [SCOI2009]迷路( dp + 矩阵快速幂 )

    递推式很明显...但是要做矩阵乘法就得拆点..我一开始很脑残地对于每一条权值v>1的边都新建v-1个节点去转移...然后就TLE了...把每个点拆成9个就可以了...时间复杂度O((9N)^3* ...

  4. 【百度地图API】圣诞节里不会迷路的麋鹿——驾车导航

    原文:[百度地图API]圣诞节里不会迷路的麋鹿--驾车导航 任务描述: 可能大家还不知道,圣诞老人是爱迷路的老爷爷! 今年圣诞节又要到了,圣诞老人又要出来送礼物了.可是,他灰常的迷路呢! 还好,他有一 ...

  5. 1297: [SCOI2009]迷路

    1297: [SCOI2009]迷路 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 652  Solved: 442[Submit][Status] ...

  6. 【矩阵快速幂】bzoj1297 [SCOI2009]迷路

    1297: [SCOI2009]迷路 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1407  Solved: 1007[Submit][Status ...

  7. [BZOJ 1297][SCOI2009]迷路

    1297: [SCOI2009]迷路 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1418  Solved: 1017[Submit][Status ...

  8. B20J_1297_[SCOI2009]迷路_矩阵乘法

    B20J_1297_[SCOI2009]迷路_矩阵乘法 题意:有向图 N 个节点,从节点 0 出发,必须恰好在 T 时刻到达节点 N-1.总共有多少种不同的路径? 2 <= N <= 10 ...

  9. bzoj 4709 [Jsoi2011]柠檬——单调栈二分处理决策单调性

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4709 题解:https://blog.csdn.net/neither_nor/articl ...

随机推荐

  1. Word快捷选取

    在word中,你知道鼠标单击选中一个词,双击选中一行,三击选中一个段落吗?

  2. man gzip

    GZIP(1)                                                                GZIP(1) NAME/名称       gzip, g ...

  3. Ansible环境搭建

    Installation Guide(Ansible官网链接) Basics / What Will Be Installed What Version To Pick? Control Machin ...

  4. 尝试用了一哈wepy框架的感想

    恶心死我, 1 在项目里出现了中文乱码(utf-8在wpy文件里有中文和注释--编译后就转化成乱码, 把代码拷在另外的项目里,(该项目没有中文乱码现象,)编译出来就出现中文乱码, 然后我再在所拷的代码 ...

  5. SQL 介绍和操作

    1.什么是SQL SQL的全称是“结构话查询语句”(Structured Query Language ),是1974年有Boyce和chamberlin 提出来的.经过多年的发展,SQL语言已经成为 ...

  6. Linux常用命令学习记录

    兄弟连Linux培训 ,小编整理了常用的Linux学习命令: 1 cp 拷贝命令 参数:-p 文件属性一起拷贝 -r 拷贝文件夹 -d 软链信息等一起拷贝 -a 是-rdp的简写 2 find 文件查 ...

  7. php XDebug配置和使用

    已本机php 5.5nts为例,php.ini配置如下: [XDebug] xdebug.profiler_append = 0 xdebug.profiler_enable = 1 xdebug.p ...

  8. PG_CONFIG-NOTFOUND

  9. [BZOJ3262]:陌上花开(CDQ分治)

    题目传送门 题目描述 有$n$朵花,每朵花有三个属性:花形$(s)$.颜色$(c)$.气味$(m)$,用三个整数表示.现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花$A$比 ...

  10. Linux日志管理系统rsyslog

    一.日志的概念 什么是日志?日志就是历史事件.历史事件包括时间.地点.人物.时间.这个是生活中所说的日志很好理解.在Linux中也有类似的服务,它主要作用就是记录Linux系统的历史事件,包括什么时间 ...