标签:add 复杂度 min std 需要 情况 code while bellman
关于此题有一种精简的写法。
首先我们分析题面,可以发现如果最后可以达到使 \(1\) 到 \(n\) 的路径距离都相等,那么从 \(1\) 到任意一个 \(1\) 到 \(n\) 的路径上的节点的路径也都相等。所以我们设 \(dis[u]\) 为 \(1\) 到 点 \(u\) 的路径长度,\(dis[v]\) 为 \(1\) 到 \(u\) 点连向的那个点的路径长度。因为边权要么为 \(1\) 要么为 \(2\),所以我们可以得到:\(1 \leq dis[v]-dis[u] \leq 2\),即 \(\begin{cases}dis[v]\leq dis[u]+2 \\ dis[u] \leq dis[v]-1 \end{cases}\) 。
所以我们就建一条 \(u\) 到 \(v\) 的边权为 \(2\) 的边,建一条 \(v\) 到 \(u\) 的边权为 \(-1\) 的边,然后就可以跑最短路求解出答案了(注意要判负环无解的情况)。
这里其实没必要去跑 \(spfa\),因为 \(n,m\) 都很小,且 \(spfa\) 找负环的时间复杂度是 \(O(nm)\) 的,所以我用了只有五行的 \(Bellman-Ford\) 算法,时间复杂度为 \(O(nm+m)\)。
但是对于不在 \(1\) 到 \(n\) 路径上的点,我们需要找出来并不管他们,我就用了一遍 \(dfs\) 解决了,没必要建反图跑两遍 \(dfs\) 再来找打了两次标记的点。
代码精简,运行也快,因为 \(spfa\) 在随机数据下的 \(O(km)\) 复杂度,所以还是略慢于跑了两遍 \(dfs\) 的 \(spfa\)。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int ans=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch==‘-‘) f=-f;ch=getchar();}
while(isdigit(ch)){ans=(ans<<1)+(ans<<3)+ch-48;ch=getchar();}
return ans*f;
}
const int N=5005;
int n,m;
int tag[N],vis[N];
int hd[N],nx[N],to[N],from[N],tot;
void adde(int u,int v){
nx[++tot]=hd[u];to[tot]=v;hd[u]=tot,from[tot]=u;
}
int hd2[N],nx2[N<<1],to2[N<<1],tot2,val[N<<1],from2[N<<1];
void adde2(int u,int v,int w){
nx2[++tot2]=hd2[u];to2[tot2]=v;hd2[u]=tot2,val[tot2]=w,from2[tot2]=u;
}
void dfs(int u){
if(u==n) return;
for(int i=hd[u];i;i=nx[i]){
int v=to[i];
if(!vis[v]) vis[v]=1,dfs(v);
if(tag[v]) tag[u]=1;
}
}
int dis[N];
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int x=read(),y=read();
adde(x,y);
}
tag[n]=1;
dfs(1);
for(int i=1;i<=m;i++){
if(tag[from[i]]&&tag[to[i]]){
adde2(from[i],to[i],2);
adde2(to[i],from[i],-1);
}
}
memset(dis,0x7f,sizeof(dis));
dis[1]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=tot2;j++)
dis[to2[j]]=min(dis[to2[j]],dis[from2[j]]+val[j]);
for(int i=1;i<=tot2;i++)
if(dis[from2[i]]+val[i]<dis[to2[i]]) return printf("No\n"),0;
printf("Yes\n");
for(int i=1;i<=m;i++){
if(tag[from[i]]&&tag[to[i]]) printf("%d\n",dis[to[i]]-dis[from[i]]);
else printf("1\n");
}
return 0;
}
标签:add 复杂度 min std 需要 情况 code while bellman
原文地址:https://www.cnblogs.com/Quick-Kk/p/14618428.html