[一本通学习笔记] 负环

负环问题通常可以使用SPFA的dfs和bfs实现来完成。需要注意的是SPFA的bfs实现复杂度可能会飙到O(n^3)因而不适合使用,所以我们通常采用dfs实现。(虽然感觉这玩意的复杂度也不是特别稳定?)
需要注意两个问题

  • 求负环时跑最短路还是最长路要根据题意决定
  • 无需设置初态dis为infinity,否则可能会T掉

    10082. 「一本通 3.3 例 1」Word Rings

    简单的建图,注意这里要跑最长路
#include <bits/stdc++.h>
using namespace std;

vector <pair<int,double> > g[1000005];

namespace SPFA {
    int m,ins[1000005],vis[1000005],fg=0,t1,t2,t3;
    double dis[1000005];
    vector <pair<int,double> > g[1000005];
    void dfs(int p){
        ins[p]=1; vis[p]=1;
        for(int i=0;i<g[p].size()&&!fg;i++)
            if(dis[g[p][i].first]<dis[p]+g[p][i].second){
                dis[g[p][i].first]=dis[p]+g[p][i].second;
                if(ins[g[p][i].first]==0)
                    dfs(g[p][i].first);
                else {fg=1; return;}}
        ins[p]=0;
    }
    bool solve() {
        int n=1000; fg=0;
        memset(ins,0,sizeof ins);
        memset(vis,0,sizeof vis);
        for(int i=1;i<=n;i++) dis[i]=0;
        for(int i=1;i<=n;i++) {
            if(vis[i]==0)  {
                dfs(i);
            }
            if(fg) return true;
        }
        return false;
    }
}

int T,n;

inline int calc(char x,char y) {
    return (x-'a')*30+(y-'a')+1;
}

int main() {
    while(cin>>n && n) {
        string str;
        for(int i=1;i<=1000;i++)
            g[i].clear();
        for(int i=1;i<=n;i++) {
            cin>>str;
            if(str.length()>1) {
                g[calc(str[0],str[1])].push_back(make_pair(calc(str[str.length()-2],str[str.length()-1]),str.length()));
            }
        }
        double L=0,R=1e+5;
        while(R-L>1e-6) {
            double M=(L+R)/2;
            for(int i=1;i<=1000;i++)
                SPFA::g[i].clear();
            for(int i=1;i<=1000;i++)
                for(int j=0;j<g[i].size();j++)
                    SPFA::g[i].push_back(make_pair(g[i][j].first,g[i][j].second-M)); 
            if(SPFA::solve()) L=M;
            else R=M;
        }
        if(L==0) cout<<"No solution"<<endl;
        else cout<<L<<endl;
    }
} 

10083. 「一本通 3.3 例 2」双调路径

没看出这题和负环有什么关系,分层图最短路即可

#include <bits/stdc++.h>
using namespace std;

const int N=1100005;
vector <pair<int,int> > g[N];
int d[N],v[N],n,m,s,e,p,r,c,t;
void make(int t1,int t2,int t3) {
    g[t1].push_back(make_pair(t2,t3));
}
void solve(int v0) {
    queue<int>q;
    d[v0]=0; v[v0]=1;
    q.push(v0);
    while(q.size()) {
        int p=q.front();
        q.pop();
        v[p]=0;
        for(int i=0;i<g[p].size();i++) {
            int x=g[p][i].first,y=g[p][i].second;
            if(d[x]>d[p]+y) {
                d[x]=d[p]+y;
                if(!v[x]) q.push(x), v[x]=1;
            }
        }
    }
}
inline int calc(int nd,int cs) {
    return nd*10200+cs+1;
}
int main() {
    ios::sync_with_stdio(false);
    cin>>n>>m>>s>>e;
    for(int i=1;i<=m;i++) {
        cin>>p>>r>>c>>t;
        for(int j=0;j<=10000;j++) {
            make(calc(p,j),calc(r,j+c),t),
            make(calc(r,j),calc(p,j+c),t);
        }
    }
    int cnt=0;
    memset(d,0x3f,sizeof d);
    solve(calc(s,0));
    int mx=0x3f3f3f3f; 
    for(int i=0;i<=10000;i++)
        cnt+=(d[calc(e,i)]<mx?1:0),
        mx=min(mx,d[calc(e,i)]);
    cout<<cnt<<endl;
    return 0; 
}

10084. 「一本通 3.3 练习 1」最小圈

一开始dis设infinity然后狂T不止

#include <bits/stdc++.h>
using namespace std;

const int N=10005;
int ins[N],vis[N],n,m,flag;
double dis[N],M;
vector <pair<int,double> > g[N];

void dfs(int p) {
    ins[p]=vis[p]=1;
    for(int i=0;i<g[p].size()&&!flag;i++) {
        int q=g[p][i].first;
        if(dis[q]>dis[p]+g[p][i].second-M) {
            dis[q]=dis[p]+g[p][i].second-M;
            if(ins[q]) {
                flag=1;
                return;
            }
            dfs(q);
        }
        if(flag) return;
    }
    ins[p]=0;
}

int main() {
    ios::sync_with_stdio(false);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) {
        int t1,t2;double t3;
        scanf("%d%d%lf",&t1,&t2,&t3);
        g[t1].push_back(make_pair(t2,t3));
    }
    double L=-1e+7,R=1e+7;
    while(R-L>1e-9) {
        M=(L+R)/2;
        memset(vis,0,sizeof vis);
        memset(ins,0,sizeof ins);
        memset(dis,0,sizeof dis);
        flag=0;
        for(int i=1;i<=n;i++) {
            if(vis[i]==0) {
                dfs(i);
            }
            if(flag) break;
        }
        if(flag) R=M;
        else L=M;
    }
    cout<<setiosflags(ios::fixed)<<setprecision(8)<<L+1e-9<<endl;
}

10085. 「一本通 3.3 练习 2」虫洞 Wormholes

#include <bits/stdc++.h>
using namespace std;

int n,m,w,ins[1000005],vis[1000005],dis[1000005],fg=0,t1,t2,t3,T;
vector <pair<int,int> >g[1000005];

void dfs(int p) {
    ins[p]=1; vis[p]=1;
    for(int i=0;i<g[p].size()&&!fg; i++) {
        if(dis[g[p][i].first]>dis[p]+g[p][i].second) {
            dis[g[p][i].first]=dis[p]+g[p][i].second;
            if(ins[g[p][i].first]==0) dfs(g[p][i].first);
            else fg=1;
        }
    }
    ins[p]=0;
}

int main() {
    cin>>T;
    while(T--) {
        fg=0;
        memset(ins,0,sizeof ins);
        memset(vis,0,sizeof vis);
        memset(dis,0,sizeof dis);
        cin>>n>>m>>w;
        for(int i=1;i<=n;i++) g[i].clear();
        for(int i=1;i<=m;i++) {
            cin>>t1>>t2>>t3;
            g[t1].push_back(make_pair(t2,t3));
            g[t2].push_back(make_pair(t1,t3));
        }
        for(int i=1;i<=w;i++) {
            cin>>t1>>t2>>t3;
            g[t1].push_back(make_pair(t2,-t3));
        }
        for(int i=1;i<=n;i++) if(vis[i]==0) dis[i]=0, dfs(i);
        if(fg==1) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
}

10086. 「一本通 3.3 练习 3」Easy SSSP

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dis[N],vis[N],ins[N],n,m,t1,t2,t3,flag;
vector <pair<int,int> > g[N];

void dfs(int p) {
    vis[p]=ins[p]=1;
    for(int i=0;i<g[p].size();i++) {
        int q=g[p][i].first;
        if(dis[q]>dis[p]+g[p][i].second) {
            dis[q]=dis[p]+g[p][i].second;
            if(ins[q]) {
                flag=1;
                return;
            }
            else {
                dfs(q);
            }
        }
    }
    ins[p]=0;
}

void spfa(int s) {
    memset(dis,0x3f,sizeof dis);
    memset(vis,0,sizeof vis);
    queue <int> q;
    q.push(s); dis[s]=0; vis[s]=1;
    while(!q.empty()) {
        int p=q.front(); q.pop(); vis[p]=0;
        for(int i=0;i<g[p].size();i++) {
            int x=g[p][i].first, y=g[p][i].second;
            if(dis[x] > dis[p]+y) {
                dis[x] = dis[p]+y;
                if(!vis[x]) {
                    q.push(x);
                    vis[x]=1;
                }
            }
        }
    }
    for(int i=1;i<=n;i++) {
        if(dis[i]>=0x3f3f3f3f) cout<<"NoPath"<<endl;
        else cout<<dis[i]<<endl;
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin>>n>>m;
    int s;
    cin>>s;
    for(int i=1;i<=m;i++) {
        cin>>t1>>t2>>t3;
        g[t1].push_back(make_pair(t2,t3));
    }
    for(int i=1;i<=n;i++) {
        if(vis[i]==0) {
            dfs(i);
        }
        if(flag) break;
    }
    if(flag) {
        cout<<"-1"<<endl;
    }
    else {
        spfa(s);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/11621466.html