【题意】给定n个点的图,正权无向边,正负权有向边,保证对有向边(u,v),v无法到达u,求起点出发到达所有点的最短距离。

【算法】拓扑排序+dijkstra

【题解】因为有负权边,直接对原图进行spfa,加slf优化后可过,但是这道题就没意思了。

理论上,最短路问题用spfa是不能保证复杂度的,但dijkstra的问题是不能处理负权边。

因为题目保证不能返回,实际上有向边将全图分成了几个部分。如果把仅由无向边连接的连通块看成点,则原图变成DAG。

对连通块内部进行dijkstra,在DAG上用拓扑序递推计算就可以保证O(n log n)出解。

具体实现:全图共用最短距离数组d[]。

对跨越连通块的有向边建新图,先用部分拓扑序删掉不从s出发的点。

开连通块个数的堆。

然后拓扑排序的过程中将到达别的连通块的点加入对应的堆,dijkstra时直接开始不用设置初始状态。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<queue>
using namespace std;
const int maxn=,inf=0x3f3f3f3f;
int first[maxn],FIRST[maxn],d[maxn],col[maxn],in[maxn],A[maxn],B[maxn];
int tot,cnt,n,m,N,M,s,color;
struct edge{int v,w,from;}e[maxn*],E[maxn*];
struct cyc{
int x,d;
bool operator < (const cyc &a)const{
return d>a.d;//
}
};
priority_queue<cyc>q[maxn];
int read(){
char c;int s=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
void INSERT(int u,int v,int w){cnt++;E[cnt].v=v;E[cnt].w=w;E[cnt].from=FIRST[u];FIRST[u]=cnt;in[v]++;}
void dfs(int x,int color){
col[x]=color;
for(int i=first[x];i;i=e[i].from)if(!col[e[i].v]){
dfs(e[i].v,color);
}
}
queue<int>Q;
void dijkstra(int k){
while(!q[k].empty()){
cyc y=q[k].top();q[k].pop();
if(y.d!=d[y.x])continue;
int x=y.x;
for(int i=first[x];i;i=e[i].from)if(d[e[i].v]>d[x]+e[i].w){
d[e[i].v]=d[x]+e[i].w;
q[k].push((cyc){e[i].v,d[e[i].v]});
}
}
}
int main(){
scanf("%d%d%d%d",&n,&m,&M,&s);
for(int i=;i<=m;i++){
int u=read(),v=read(),w=read();
insert(u,v,w);insert(v,u,w);
}
for(int i=;i<=n;i++)if(!col[i])dfs(i,++N);
for(int i=;i<=M;i++){
int u=read(),v=read(),w=read();
INSERT(col[u],col[v],w);
A[i]=u;B[i]=v;
}
for(int i=;i<=N;i++)if(!in[i]&&col[s]!=i)Q.push(i);
while(!Q.empty()){
int x=Q.front();Q.pop();
for(int i=FIRST[x];i;i=E[i].from){
in[E[i].v]--;
if(!in[E[i].v]&&col[s]!=E[i].v)Q.push(E[i].v);
}
}
Q.push(col[s]);
memset(d,0x3f,sizeof(d));d[s]=;q[col[s]].push((cyc){s,});
while(!Q.empty()){
int x=Q.front();Q.pop();
dijkstra(x);
for(int i=FIRST[x];i;i=E[i].from){
if(d[B[i]]>d[A[i]]+E[i].w){
d[B[i]]=d[A[i]]+E[i].w;
q[E[i].v].push((cyc){B[i],d[B[i]]});
}
in[E[i].v]--;
if(!in[E[i].v])Q.push(E[i].v);
}
}
for(int i=;i<=n;i++)if(d[i]<inf)printf("%d\n",d[i]);else printf("NO PATH\n");
return ;
}

dijkstra使用小根堆!每次加入距离最小的点。最致命的是写成大根堆也可以跑出答案,但是大数据就会很慢。

dijkstra使用小根堆!

dijkstra使用小根堆!

dijkstra使用小根堆!

dijkstra使用小根堆!

dijkstra使用小根堆!

dijkstra使用小根堆!

dijkstra使用小根堆!

dijkstra使用小根堆!

dijkstra使用小根堆!

【BZOJ】2200: [Usaco2011 Jan]道路和航线的更多相关文章

  1. [BZOJ 2200][Usaco2011 Jan]道路和航线 spfa+SLF优化

    Description Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T.这些城镇之间通过R条 ...

  2. bzoj 2200: [Usaco2011 Jan]道路和航线——拓扑+dijkstra

    Description Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T.这些城镇之间通过R条 ...

  3. BZOJ 2200: [Usaco2011 Jan]道路和航线

    Description Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T.这些城镇之间通过R条 ...

  4. bzoj 2200: [Usaco2011 Jan]道路和航线【spfa】

    直接跑最短路就行了--还不用判负环 #include<iostream> #include<cstdio> #include<queue> using namesp ...

  5. 2200: [Usaco2011 Jan]道路和航线 (拓扑排序+dijstra)

    Description Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T.这些城镇之间通过R条 ...

  6. [Usaco2011 Jan]道路和航线

    Description Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T.这些城镇之间通过R条 ...

  7. bzoj2200: [Usaco2011 Jan]道路和航线

    先忽略航线,求出图中所有连通块,再用航线拓扑排序求出每个连通块的优先级 然后dijkstra时优先处理优先级高的块里的点就行了 ps:这题SPFA会TLE #include <iostream& ...

  8. BZOJ 2200--[Usaco2011 Jan]道路和航线(最短路&拓扑排序)

    2200: [Usaco2011 Jan]道路和航线 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1128  Solved: 414[Submit] ...

  9. BZOJ 2199: [Usaco2011 Jan]奶牛议会

    2199: [Usaco2011 Jan]奶牛议会 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 375  Solved: 241[Submit][S ...

随机推荐

  1. A4

    队名:起床一起肝活队 组长博客:博客链接 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过去两天完成了哪些任务 描述: 很胖,刚学,照猫画虎做了登录与注册界面. 展示GitHub ...

  2. 如何修改git push时的密码

    如何修改git push时的密码 如下: 打开git bash 输入 cd ~/.ssh ls 确定有 id_rsa 和 id_rsa.pub文件 ssh-keygen -p -f id_rsa 第一 ...

  3. 内存转储文件调试系统崩溃bug

    百度百科:内存转储文件 内存转储是用于系统崩溃时,将内存中的数据转储保存在转储文件中,供给有关人员进行排错分析用途.而它所保存生成的文件就叫做内存转储文件. 内存转储文件也被称作虚拟内存,它是用硬盘里 ...

  4. parse_str — 将字符串解析成多个变量

    $arr2="first=value1&second=value2&third[]=value3&third[]=value4"; parse_str($a ...

  5. Ubuntu编译内核树

    什么是内核树?刚开始我也没弄明白,通过这几天的学习,有所感悟,就说说我的理解吧!从形式上看,内核树与内核源码的目录结构形式是相同的,都是由各个层次的文件目录结构组成,但是其中的具体内容肯定是不同的.从 ...

  6. 【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp

    题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:对于u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径. ...

  7. 【bzoj1877】[SDOI2009]晨跑 费用流

    题目描述 Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑.仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑. 现在给出一张学校附近的地图,这张地图中包含N个十字路口和M条街 ...

  8. BZOJ3167/BZOJ4824 HEOI2013SAO/CQOI2017老C的键盘(树形dp)

    前者是后者各方面的强化版. 容易想到设f[i][j]表示i子树中第j小的是i的方案数(即只考虑相对关系).比较麻烦的在于转移.考虑逐个合并子树.容易想到枚举根原来的排名和子树根原来的排名,算一发组合数 ...

  9. 【题解】51nod 1203JZPLCM问题

    这题好强强啊,貌似是集训队原题?集训队原题当中值域是1e9的范围,这样各种乱搞是妥妥的不能过了,只能写正解的离线+树状数组维护前缀积. 最开始我写了几种乱搞做法,包括莫队和线段树做法.其中表现比较优秀 ...

  10. CF724E Goods transportation 最小割 DP

    照惯例CF的题不放原题链接... 题意:一个序列上有n个点,每个点有权值pi和si.表示这个点一开始有pi个物品,最多可以卖出si个物品,每个点都可以把物品向编号更大的点运输,但是对于i < j ...