最短路
单源最短路
dijkstra堆优化 O(nlogn)
不能处理负边权
每次从队里拽出来打标记
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int M=1e6+10;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n,m,s;
int hd[N],to[M],nxt[M],tot,w[M];
inline void add(int x,int y,int z) {
to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
}
struct node{
int u,val;
bool operator < (const node &w) const {
return val>w.val;
}
node(){}
node(int u_,int v_):u(u_),val(v_){}
};
priority_queue< node >q;
int dis[N];
bool vis[N];
void dij() {
for(int i=0;i<=n;i++) dis[i]=0x7fffffff;
dis[s]=0;
q.push(node(s,0));
while(q.size()) {
int x=q.top().u;q.pop();
if(vis[x]) continue;
vis[x]=1;
for(int i=hd[x];i;i=nxt[i]) {
int y=to[i];
if(dis[y]>dis[x]+w[i]) {
dis[y]=dis[x]+w[i];
if(!vis[y]) q.push(node(y,dis[y]));
}
}
}
}
int main() {
n=read();m=read();s=read();
for(int i=1,u,v,ww;i<=m;i++) {
u=read(),v=read(),ww=read();
add(u,v,ww);
}
dij();
for(int i=1;i<n;i++)
printf("%d ",dis[i]);
printf("%d
",dis[n]);
return 0;
}
线段树优化建图
spfa 稀疏图 (O(n)) 稠密 (O(n*m))
每次从队里拽出来是(vis)标记清空
然后入队打标记
void spfa() {
memset(dis,0x3f,sizeof(dis));
q.push(s);
dis[s]=0;
while(q.size()) {
int x=q.front();q.pop();
vis[x]=0;
for(int i=hd[x];i;i=nxt[i]) {
int y=to[i];
if(dis[y]>dis[x]+w[i]) {
dis[y]=dis[x]+w[i];
if(!vis[y]) {vis[y]=1;q.push(y);}
}
}
}
}
判负环
开个 cnt [ ] ,更新(一定是入队次数) >n 次说明有负环
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=2005;
const int M=1e5+10;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n,m;
int hd[N],to[M],tot,nxt[M],w[M];
inline void add(int x,int y,int z) {
to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
}
queue<int>q;
int dis[N],cnt[N];
bool vis[N];
bool spfa() {
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
while(q.size()) q.pop();
q.push(1);
dis[1]=0;cnt[1]=1;
while(q.size()) {
int x=q.front();q.pop();
vis[x]=0;
for(int i=hd[x];i;i=nxt[i]) {
int y=to[i];
if(dis[y]>dis[x]+w[i]) {
dis[y]=dis[x]+w[i];
if(++cnt[y]>n) return 1;
if(!vis[y]) {vis[y]=1;q.push(y);}
}
}
}
return 0;
}
int main() {
int T=read();
while(T--) {
tot=0;
memset(hd,0,sizeof(hd));
n=read();m=read();
for(int i=1;i<=m;i++) {
int u=read(),v=read(),w=read();
if(w>=0) add(u,v,w),add(v,u,w);
else add(u,v,w);
}
puts(spfa()?"YES":"NO");
}
return 0;
}
SLF
将原队列改成双端队列,对要加入队列的点 (p),如果 (dis[p]) 小于队头元素(u) 的(dist[u]),将其插入到队头,否则插入到队尾。
#include <deque>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1e4+10;
const int M=1e6+10;
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n,m,s;
int hd[N],w[M],to[M],nxt[M],tot;
inline void add(int x,int y,int z) {
to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
}
deque<int>Q;
int dis[N];
bool vis[N];
void spfa() {
for(int i=1;i<=n;i++)
dis[i]=0x7fffffff;
Q.push_back(s);
dis[s]=0;vis[s]=1;
while(Q.size()) {
int x=Q.front();Q.pop_front();
vis[x]=0;
for(int i=hd[x];i;i=nxt[i]) {
int y=to[i];
if(dis[y]>dis[x]+w[i]) {
dis[y]=dis[x]+w[i];
if(!vis[y]) {
vis[y]=1;
if(!Q.empty()&&dis[y]<dis[Q.front()]) Q.push_front(y);
else Q.push_back(y);
}
}
}
}
}
int main() {
n=read();m=read();s=read();
for(int i=1,x,y,z;i<=m;i++) {
x=read();y=read();z=read();
add(x,y,z);
}
spfa();
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}
LLL
对每个要出队的队头元素 (u),比较 (dist[u])和队列中点的 $dist $的平均值,如果 (dist[u]) 更大,将其弹出放到队尾,然后取队首元素进行相同操作,直到队头元素的 (dist)小于等于平均值。
超级源点,超级会点
Description
为了提高服务器的耐受能力,很多流量大的网站都会架设多台服务器,而互联网的路由能找到线路最短的一台服务器。 现在UOI想要下片,他有好多台电脑,又有好多服务器可以提供下载。UOI将给你一个网络图,告诉你点点之间的线路长度,问最短的线路长是多少,以及选择的那台用来下载的电脑和被选的服务器的编号。 如果有多台电脑/服务器之间连线都是最短线路,输出电脑编号最小的;如果还有多种选择,输出服务器编号最小的。
输入格式
第一行n,m,表示总格有n个点,m条网络连线 接下来m行,表示每条网络连线所连接的A、B点和线的长度。 接下来一个数T1,表示UOI有多少台电脑。 下一行T1个数,表示UOI每台电脑的编号。 接下来一个数T2,表示有多少台服务器。 下一行T2个数,表示每台服务器编号。
输出格式
三个数,分别是线路长度,UOI下载用的电脑,提供片的下载源
输入输出样例
输入 #1复制
5 3
2 3 2
1 4 2
1 5 2
2
1 2
2
3 5
输出 #1复制
2 1 5
说明/提示
对于30%的数据,N<=100,M<=N^2 对于100%的测试数据,N<=100000,M<=400000,T1+T2<=N,其余数据在10^9以内,且大于0
Solution
这道题就是个最短路$spfa $
很难想到的是建立超级源点和超级汇点;
然后开个(find[])记录连接情况
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define re register int
#define N 100005
#define M 400005
using namespace std;
int t1,t2,s[N],fd[N];
long long ans=0x7ffffff;
struct edge{
int v,w,nxt;
}e[M<<1];
int hd[N],cnt=0,n,m,dis[N];
bool vis[N];
queue<int>q;
inline void add(int u,int v,int w){
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nxt=hd[u];
hd[u]=cnt;
}
int main(){
memset(dis,0x3f,sizeof(dis));
scanf("%d%d",&n,&m);
for (re i=1;i<=m;i++) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
scanf("%d",&t1);
for(re i=1;i<=t1;i++)
scanf("%d",&s[i]);
sort(s+1,s+1+t1);
scanf("%d",&t2);
int x;
for(re i=1;i<=t2;i++){
scanf("%d",&x);
fd[x]=x;
q.push(x);
dis[x]=0;
vis[x]=1;
}
while(!q.empty()){
x=q.front();q.pop();vis[x]=0;
for(int i=hd[x];i;i=e[i].nxt){
int to=e[i].v;
if(dis[to]>dis[x]+e[i].w){
dis[to]=dis[x]+e[i].w;
fd[to]=fd[x];
if(!vis[to]){
q.push(to);vis[to]=1;
}
}
}
}
int u;
for(int i=1;i<=t1;i++)
if(dis[s[i]]<ans)
ans=dis[s[i]],u=s[i];
printf("%lld %d %d",ans,u,fd[u]);
return 0;
}
多源最短路(任意两点距离)
Floyd O( (n^3) )
for(re k=1;k<=n;k++)
for(re i=1;i<=n;i++)
for(re j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
注意循环的顺序
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int res=0;bool f=1;char c;c=getchar();
while(!isdigit(c)){if(c=='-')f=0;c=getchar();}
while(isdigit(c)){res=res*10+(c^48);c=getchar();}
return f?res:-res;
}
#define N 205
#define inf 0x3f3f3f3f
int n,m,q,k;
int f[N][N],t[N];
int main(){
n=read();m=read();
memset(f,0x3f,sizeof(f));
memset(t,0x3f,sizeof(t));
for(int i=0;i<n;i++)t[i]=read(),f[i][i]==0;
for(int i=0,x,y,z;i<m;i++){
x=read();y=read();z=read();
f[x][y]=f[y][x]=z;
}
q=read();
while(q--){
int x=read(),y=read(),z=read();
while(z>=t[k]){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(f[i][j]>f[i][k]+f[k][j])
f[i][j]=f[i][k]+f[k][j];
k++;
}
if(f[x][y]==inf || t[x]>z ||t[y]>z)puts("-1");
else printf("%d
",f[x][y]);
}
return 0;
}
传递闭包
http://poj.org/problem?id=1094
for(int i=1;i<=n;i++)
d[i][i]=1;
for(int i=1;i<=m;i++){
x=read();y=read();
d[x][y]=d[y][x];
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]|=d[i][k]&d[k][j];
Johnson 全源最短路
先跑(spfa)解决负权问题,然后跑(n)遍(dij)
#include<bits/stdc++.h>
#define INF 1e9
using namespace std;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w,next;
}e[10005];
struct node{
int dis,id;
bool operator<(const node&a)const{
return dis>a.dis;
}
node(int d,int x){
dis=d,id=x;
}
};
int head[5005],vis[5005],t[5005];
int cnt,n,m;
long long h[5005],dis[5005];
void addedge(int u,int v,int w){
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt;
}
bool spfa(int s){
queue<int> q;
memset(h,63,sizeof(h));
h[s]=0,vis[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
if(h[v]>h[u]+e[i].w)
{
h[v]=h[u]+e[i].w;
if(!vis[v]){
vis[v]=1;
q.push(v);
t[v]++;
if(t[v]==n)return false;
}
}
}
}
return true;
}
void dijkstra(int s)
{
priority_queue<node> q;
for(int i=1;i<=n;i++)
dis[i]=INF;
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push(node(0,s));
while(!q.empty()){
int u=q.top().id;
q.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=head[u];i;i=e[i].next){
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
if(!vis[v])q.push(node(dis[v],v));
}
}
}
return;
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int u,v,w;
u=read();v=read();w=read();
addedge(u,v,w);
}
for(int i=1;i<=n;i++)
addedge(0,i,0);
if(!spfa(0)){
cout<<-1<<endl;
return 0;
}
for(int u=1;u<=n;u++)
for(int i=head[u];i;i=e[i].next)
e[i].w+=h[u]-h[e[i].v];
for(int i=1;i<=n;i++){
dijkstra(i);
long long ans=0;
for(int j=1;j<=n;j++){
f(dis[j]==INF)ans+=j*INF;
else ans+=j*(dis[j]+h[j]-h[i]);
}
cout<<ans<<endl;
}
return 0;
}
分层图最短路
例1:飞行路线
一共建(k+1)层图。各层内部正常连边,各层之间从上到下连权值为(0)的边。每向下跑一层,就相当于免费搭一次飞机。跑一遍从(s)到 (t+n∗k)的最短路即可。(注意最后(ans)取(0<=i<=k)最小)
时间复杂度:(O(k*(m+n)log(n)))
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=10005;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n,m,k;
int hd[N],to[N*10],tot,nxt[N*10],w[N*10];
inline void add(int x,int y,int z) {
to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
}
int s,t;
int dis[N][12];
struct node{
int u,d,dep;
node(){}
node(int uu,int dd,int dp){u=uu;d=dd;dep=dp;}
bool operator < (const node &x) const {
return d>x.d;
}
};
bool vis[N][12];
priority_queue<node>q;
void dij() {
memset(dis,0x3f,sizeof(dis));
q.push(node(s,0,0));
dis[s][0]=0;
while(q.size()) {
int x=q.top().u,dep=q.top().dep; q.pop();
if(vis[x][dep]) continue;
vis[x][dep]=1;
for(int i=hd[x];i;i=nxt[i]) {
int y=to[i];
if(dis[y][dep]>dis[x][dep]+w[i]) {
dis[y][dep]=dis[x][dep]+w[i];
if(!vis[y][dep]) q.push(node(y,dis[y][dep],dep));
}
if(dep<k&&dis[y][dep+1]>dis[x][dep]) {
dis[y][dep+1]=dis[x][dep];
if(!vis[y][dep+1]) q.push(node(y,dis[y][dep+1],dep+1));
}
}
}
}
int main() {
n=read();m=read();k=read();
s=read()+1;t=read()+1;
for(int i=1;i<=m;i++) {
int a=read()+1,b=read()+1,c=read();
add(a,b,c);add(b,a,c);
}
dij();
int ans=0x3f3f3f3f;
for(int i=0;i<=k;i++)
ans=min(ans,dis[t][i]);
printf("%d
",ans);
return 0;
}
例2:冻结
#include<bits/stdc++.h>
using namespace std;
#define M 500005
int hd[M<<1],to[M<<1],nxt[M<<1],w[M<<1];
int n,m,k,tot;
void add(int x,int y,int z){
to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
}
struct node{
int u,val,dep;
node(){}
node(int a,int b,int c):u(a),dep(b),val(c){}
bool operator < (const node &x)const{
return val>x.val;
}
};
priority_queue< node > Q;
int dis[M][55];
bool vis[M][55];
void dij(){
memset(dis,0x3f,sizeof(dis));
dis[1][0]=0;
Q.push(node(1,0,0));
while(Q.size()){
int dep=Q.top().dep,x=Q.top().u;
Q.pop();
if(vis[x][dep])continue;
vis[x][dep]=1;
for(int i=hd[x];i;i=nxt[i]){
int y=to[i];
if(dis[x][dep]+w[i]<dis[y][dep]){
dis[y][dep]=dis[x][dep]+w[i];
Q.push(node(y,dep,dis[y][dep]));
}
if(dep<=k&&dis[x][dep]+w[i]/2<dis[y][dep+1]){
dis[y][dep+1]=dis[x][dep]+w[i]/2;
Q.push(node(y,dep+1,dis[y][dep+1]));
}
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dij();
int ans=0x3f3f3f3f;
for(int i=0;i<=k;i++)ans=min(ans,dis[n][i]);
printf("%d
",ans);
return 0;
}
最短路计数
在求最短路的同时维护(num)数组即可,这里特殊处理距离相等的情况
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1000005;
const int mod=100003;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n,m;
int hd[N],to[N<<2],tot,nxt[N<<2];
inline void add(int x,int y) {
to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
}
int dis[N],num[N];
struct node{
int u,d;
node(){}
node(int uu,int dd){u=uu;d=dd;}
bool operator < (const node &x) const {
return d>x.d;
}
};
bool vis[N];
priority_queue<node>q;
void dij() {
memset(dis,0x3f,sizeof(dis));
q.push(node(1,0));
dis[1]=0;
num[1]=1;
while(q.size()) {
int x=q.top().u; q.pop();
if(vis[x]) continue;
vis[x]=1;
for(int i=hd[x];i;i=nxt[i]) {
int y=to[i];
if(dis[y]>dis[x]+1) {
dis[y]=dis[x]+1;
num[y]=num[x];
if(!vis[y]) q.push(node(y,dis[y]));
}
else if(dis[y]==dis[x]+1) {
num[y]+=num[x];num[y]%=mod;
if(!vis[y]) q.push(node(y,dis[y]));
}
}
}
}
int main() {
n=read();m=read();
for(int i=1;i<=m;i++) {
int a=read(),b=read();
add(a,b);add(b,a);
}
dij();
for(int i=1;i<=n;i++)
printf("%d
",num[i]);
return 0;
}
Telephone Lines S
求出(1)到(n)的路径中第(k+1)大的边权尽量小
由于答案具有单调性,我们二分花费,把(w>mid)的看成(1) ,(w<=mid)的看成(0),然后求 (1—n)的最短路,不超过(k)即合法
这里用到双端(bfs)((0)扔前面,(1)扔后面)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <deque>
using namespace std;
const int N=20005;
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x;
}
int n,m,k;
int hd[N<<1],tot=0;
struct edge{
int to,nxt,w;
}e[N<<1];
inline void add(int x,int y,int z){
e[++tot].to=y;e[tot].w=z;e[tot].nxt=hd[x];hd[x]=tot;
}
int dis[N];
bool vis[N];
bool check(int mid){
deque <int> q;
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[1]=0;q.push_front(1);
while(!q.empty()){
int x=q.front();q.pop_front();
if(vis[x]) continue;
vis[x]=1;
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to,z=e[i].w>mid?1:0;
if(dis[y]>dis[x]+z){
dis[y]=dis[x]+z;
if(!vis[y]){
if(!z) q.push_front(y);
else q.push_back(y);
}
}
}
}
if(dis[n]>k) return 0;
else return 1;
}
int mi=0x3f3f3f3f,mx;
int main(){
n=read();m=read();k=read();
for(int i=1,a,b,c;i<=m;i++){
a=read();b=read();c=read();
add(a,b,c);add(b,a,c);
mx=max(mx,c);
}
int l=1,r=mx,ans=-1;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d
",ans);
return 0;
}
(spfa)版本
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N=20005;
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x;
}
int n,m,k;
int hd[N<<1],tot=0;
struct edge{
int to,nxt,w;
}e[N<<1];
inline void add(int x,int y,int z){
e[++tot].to=y;e[tot].w=z;e[tot].nxt=hd[x];hd[x]=tot;
}
int dis[N];
bool vis[N];
queue<int>q;
bool check(int mid){
for(int i=1;i<=n;i++) {
dis[i]=0x3f3f3f3f;
vis[i]=0;
}
q.push(1); dis[1]=0; vis[1]=1;
while(!q.empty()){
int u=q.front();
q.pop(); vis[u]=0;
for(int i=hd[u];i;i=e[i].nxt){
int v=e[i].to,z=e[i].w>mid?1:0;
if(dis[v]>dis[u]+z){
dis[v]=dis[u]+z;
if(!vis[v]) {
vis[v]=1;
q.push(v);
}
}
}
}
if(dis[n]>k) return 0;
else return 1;
}
int mi=0x3f3f3f3f,mx;
int main(){
n=read();m=read();k=read();
for(int i=1,a,b,c;i<=m;i++){
a=read();b=read();c=read();
add(a,b,c);add(b,a,c);
mx=max(mx,c);
}
int l=1,r=mx,ans=-1;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d
",ans);
return 0;
}
最优贸易
建反图的思想
正着跑个从(1)到(x)的最小值
反着跑个从(1)(反图是(n))到(x)的最大值
每个节点做差
#include <queue>
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;
const int N=100005;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n,m;
int hd[N],val[N];
int to[N<<2],tot,nxt[N<<2],w[N<<2];
inline void add(int x,int y,int z) {
to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
}
vector< pair<int,int> >G[N];
#define MP make_pair
inline void add2(int x,int y,int z){
}
bool vis[N];
int dis[N],disf[N];
queue<int>q;
void spfa(){
q.push(1);
while(!q.empty()) {
int x=q.front();q.pop();
vis[x]=0;
for(int i=hd[x];i;i=nxt[i]) {
int y=to[i];
if(dis[y]>min(dis[x],w[i])) {
dis[y]=min(dis[x],w[i]);
if(!vis[y]) q.push(y),vis[y]=1;
}
}
}
}
void spfa_fan(){
q.push(n);
while(!q.empty()) {
int x=q.front();q.pop();
vis[x]=0;
for(unsigned int i=0;i<G[x].size();i++) {
int y=G[x][i].first,z=G[x][i].second;
if(disf[y]<max(disf[x],z)) {
disf[y]=max(disf[x],z);
if(!vis[y]) q.push(y),vis[y]=1;
}
}
}
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++) val[i]=read();
for(int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
add(x,y,val[y]);
G[y].push_back(MP(x,val[x]));
if(z==2) {
add(y,x,val[x]);
G[x].push_back(MP(y,val[y]));
}
}
memset(dis,0x3f,sizeof(dis));
spfa();
memset(vis,0,sizeof(vis));
memset(disf,0,sizeof(disf));
spfa_fan();
int ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,disf[i]-dis[i]);
printf("%d",ans);
return 0;
}
道路与航线
速度限制 最短路变形+输出边
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
const int N=30005;
int n,m,d;
int head[N],vis[N][505],to[N],V[N],L[N],cnt,nxt[N],prx[N][505],prv[N][505];
double z[N][505];
void qxx(int x,int y,int v,int l){
cnt++;nxt[cnt]=head[x];head[x]=cnt;to[cnt]=y;V[cnt]=v;L[cnt]=l;
}
struct node{
int pos,val;
node(int P,int VAL){
pos=P;val=VAL;
}
};
void print(int x,int y){
if(x!=1)print(prx[x][y],prv[x][y]);
printf("%d ",x-1);
}
void spfa(){
memset(z,66,sizeof(z));
queue<node>q;
vis[1][70]=1;
z[1][70]=0;
q.push(node(1,70));
while(!q.empty()){
node k=q.front();q.pop();vis[k.pos][k.val]=0;
for(register int i=head[k.pos];i;i=nxt[i]){
int t=to[i];
if(!V[i]){
if(z[k.pos][k.val]+1.0*L[i]/k.val<z[t][k.val]){
z[t][k.val]=z[k.pos][k.val]+1.0*L[i]/k.val;
prx[t][k.val]=k.pos;
prv[t][k.val]=k.val;
if(!vis[t][k.val]){
q.push(node(t,k.val));
vis[t][k.val]=1;
}
}
}
else{
int ms=V[i];
if(z[k.pos][k.val]+1.0*L[i]/ms<z[t][ms]){
z[t][ms]=z[k.pos][k.val]+1.0*L[i]/ms;
prx[t][ms]=k.pos;
prv[t][ms]=k.val;
if(!vis[t][ms]){
q.push(node(t,ms));
vis[t][ms]=1;
}
}
}
}
}
double minv=1<<30;int ans=0;
for(register int i=1;i<=500;i++){
if(minv>z[d][i]){
minv=z[d][i];ans=i;
}
}
print(prx[d][ans],prv[d][ans]);
}
int main(){
n=read();m=read();d=read();d++;
for(register int i=1;i<=m;i++){
int x=read()+1,y=read()+1,v=read(),l=read();
qxx(x,y,v,l);
}
spfa();
printf("%d",d-1);
return 0;
}
[bzoj 4398] 福慧双修
求从1号点出发,经过至少另一个点,走的边不重复的最小简单环。
发现对于简单环上和1号点相接的两个点的二进制表示上一定有至少一位不一样。
我们就把它二进制分组,然后在dij的时候就可以看看当前的to如果是1的话现在的点如果是分在出发点区域的就不行。
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int N=40005;
struct Node {
int id,dis;
bool operator < (const Node &rhs) const {
return dis>rhs.dis;}
};
priority_queue<Node>q;
int n,m,dis[N],ans,head[N],ecnt;
struct Edge{int to,nxt,val;}e[N*5];
void add(int bg,int ed,int val) {e[++ecnt]=(Edge){ed,head[bg],val};head[bg]=ecnt;}
void dij(int a,int b) {
memset(dis,0x3f,sizeof dis);
for(int i=head[1];i;i=e[i].nxt)
if((e[i].to&a)==b)
q.push((Node){e[i].to,e[i].val}),dis[e[i].to]=e[i].val;
while(!q.empty()) {
Node u=q.top();q.pop();
if(u.dis!=dis[u.id]) continue;
for(int i=head[u.id];i;i=e[i].nxt) {
if(e[i].to==1) {
if((u.id&a)!=b)
ans=min(ans,dis[u.id]+e[i].val);
continue;
}
if(dis[u.id]+e[i].val<dis[e[i].to])
dis[e[i].to]=dis[u.id]+e[i].val,
q.push((Node){e[i].to,dis[e[i].to]});
}
}
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1,a,b,c,d;i<=m;i++)
scanf("%d%d%d%d",&a,&b,&c,&d),add(a,b,c),add(b,a,d);
ans=0x3f3f3f3f;
for(int i=1;i<=n;i<<=1) {
dij(i,i);
dij(i,0);
}
cout<<ans;
return 0;
}