• [一本通学习笔记] 负环


    负环问题通常可以使用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;
    }
    
  • 相关阅读:
    JCreator的配置
    哈夫曼编码
    最小生成树
    逻辑左移右移与算术左移右移
    原码 反码 补码 移码
    hdu 小希的迷宫
    (二)Qt窗口应用程序Widget
    (一)Qt5模块,QtCreator常用快捷键,命名规范
    if __name__="__main__"
    数据库之sql语句汇总
  • 原文地址:https://www.cnblogs.com/mollnn/p/11621466.html
Copyright © 2020-2023  润新知