zoukankan      html  css  js  c++  java
  • POJ 3259 Wormholes(bellman_ford,判断有没有负环回路)

    题意:John的农场里field块地,path条路连接两块地,hole个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。我们的任务是知道会不会在从某块地出发后又回来,看到了离开之前的自己。

    思路:

    这题就是判断存不存在负环回路。

    前M条是双向边,后面的W是单向的负边。

    为了防止出现不连通,增加一个结点作为起点。起点到所有点的长度为0

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <vector>
    using namespace std;
    /*
    * 单源最短路bellman_ford算法,复杂度O(VE)
    * 可以处理负边权图。
    * 可以判断是否存在负环回路。返回true,当且仅当图中不包含从源点可达的负权回路
    * vector<Edge>E;先E.clear()初始化,然后加入所有边
    * 点的编号从1开始
    */
    const int INF = 0x3f3f3f3f;
    const int MAXN = 550;
    int dist[MAXN];
    struct Edge
    {
    	int u, v;
    	int cost;
    	Edge(int _u = 0, int _v = 0, int _cost = 0) :u(_u), v(_v), cost(_cost){}
    };
    vector<Edge> E;
    bool bellman_ford(int start, int n)//点的编号从1开始
    {
    	for (int i = 1; i <= n; i++)dist[i] = INF;
    	dist[start] = 0;
    	for (int i = 1; i<n; i++)//最多做n-1次
    	{
    		bool flag = false;
    		for (int j = 0; j<E.size(); j++)
    		{
    			int u = E[j].u;
    			int v = E[j].v;
    			int cost = E[j].cost;
    			if (dist[v]>dist[u] + cost)
    			{
    				dist[v] = dist[u] + cost;
    				flag = true;
    			}
    		}
    		if (!flag)return true;//没有负环回路
    	}
    	for (int j = 0; j<E.size(); j++)
    	if (dist[E[j].v]>dist[E[j].u] + E[j].cost)
    		return false;//第n次更新则有负环回路
    	return true;//没有负环回路
    }
    
    int main()
    {
    	int T;
    	int N, M, W;
    	int a, b, c;
    	scanf("%d", &T);
    	while (T--)
    	{
    		scanf("%d%d%d", &N, &M, &W);
    		E.clear();
    		while (M--)
    		{
    			scanf("%d%d%d", &a, &b, &c);
    			E.push_back(Edge(a, b, c));
    			E.push_back(Edge(b, a, c));
    		}
    		while (W--)
    		{
    			scanf("%d%d%d", &a, &b, &c);
    			E.push_back(Edge(a, b, -c));
    		}
    		for (int i = 1; i <= N; i++)
    			E.push_back(Edge(N + 1, i, 0));
    		if (!bellman_ford(N + 1, N + 1))printf("YES
    ");
    		else printf("NO
    ");
    	}
    	return 0;
    }

    (2) 如果一开始对所有顶点i,都把dist[i]初始化为0,那么可以检查出所有的负圈

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <vector>
    using namespace std;
    /*
    * 单源最短路bellman_ford算法,复杂度O(VE)
    * 可以处理负边权图。
    * vector<Edge>E;先E.clear()初始化,然后加入所有边
    * 点的编号从1开始
    */
    const int INF = 0x3f3f3f3f;
    const int MAXN = 550;
    int dist[MAXN];
    struct Edge
    {
    	int u, v;
    	int cost;
    	Edge(int _u = 0, int _v = 0, int _cost = 0) :u(_u), v(_v), cost(_cost){}
    };
    vector<Edge> E;
    bool bellman_ford(int n)//点的编号从1开始
    {
    	for (int i = 1; i <= n; i++)dist[i] = 0;
    	for (int i = 1; i<n; i++)//最多做n-1次
    	{
    		bool flag = false;
    		for (int j = 0; j<E.size(); j++)
    		{
    			int u = E[j].u;
    			int v = E[j].v;
    			int cost = E[j].cost;
    			if (dist[v]>dist[u] + cost)
    			{
    				dist[v] = dist[u] + cost;
    				flag = true;
    			}
    		}
    		if (!flag)return true;//没有负环回路
    	}
    	for (int j = 0; j<E.size(); j++)
    	if (dist[E[j].v]>dist[E[j].u] + E[j].cost)
    		return false;//第n次更新则有负环回路
    	return true;//没有负环回路
    }
    
    int main()
    {
    	int T;
    	int N, M, W;
    	int a, b, c;
    	scanf("%d", &T);
    	while (T--)
    	{
    		scanf("%d%d%d", &N, &M, &W);
    		E.clear();
    		while (M--)
    		{
    			scanf("%d%d%d", &a, &b, &c);
    			E.push_back(Edge(a, b, c));
    			E.push_back(Edge(b, a, c));
    		}
    		while (W--)
    		{
    			scanf("%d%d%d", &a, &b, &c);
    			E.push_back(Edge(a, b, -c));
    		}
    		if (!bellman_ford(N))printf("YES
    ");
    		else printf("NO
    ");
    	}
    	return 0;
    }
    

    (3) SPFA

    某个顶点进入队列的次数超过N,则有负环

    #include <iostream>
    #include <string.h>
    #include <stdio.h>
    #include <algorithm>
    #include <vector>
    #include <queue>
    using namespace std;
    /*
    * 单源最短路SPFA
    */
    const int MAXN = 1010;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
    	int v;
    	int cost;
    	Edge(int _v = 0, int _cost = 0) :v(_v), cost(_cost){}
    };
    
    vector<Edge> E[MAXN];
    
    void addedge(int u, int v, int w)
    {
    	E[u].push_back(Edge(v, w));
    }
    
    bool vis[MAXN];
    int cnt[MAXN];
    int dist[MAXN];
    
    bool SPFA(int start, int n)
    {
    	memset(vis, false, sizeof(vis));
    	for (int i = 1; i <= n; i++)dist[i] = INF;
    	dist[start] = 0;
    	vis[start] = true;
    	queue<int>que;
    	while (!que.empty())que.pop();
    	que.push(start);
    	memset(cnt, 0, sizeof(cnt));
    	cnt[start] = 1;
    	while (!que.empty())
    	{
    		int u = que.front();
    		que.pop();
    		vis[u] = false;
    		for (int i = 0; i<E[u].size(); i++)
    		{
    			int v = E[u][i].v;
    			if (dist[v]>dist[u] + E[u][i].cost)
    			{
    				dist[v] = dist[u] + E[u][i].cost;
    				if (!vis[v])
    				{
    					vis[v] = true;
    					que.push(v);
    					if (++cnt[v]>n)return false;
    					//有负环回路
    				}
    			}
    		}
    	}
    	return true;
    }
    int main()
    {
    	int T;
    	int N, M, W;
    	int a, b, c;
    	scanf("%d", &T);
    	while (T--)
    	{
    		scanf("%d%d%d", &N, &M, &W);
    		for (int i = 1; i <= N + 1; i++)E[i].clear();
    		while (M--)
    		{
    			scanf("%d%d%d", &a, &b, &c);
    			addedge(a, b, c);
    			addedge(b, a, c);
    		}
    		while (W--)
    		{
    			scanf("%d%d%d", &a, &b, &c);
    			addedge(a, b, -c);
    		}
    		for (int i = 1; i <= N; i++)
    			addedge(N + 1, i, 0);
    		if (!SPFA(N + 1, N + 1))printf("YES
    ");
    		else printf("NO
    ");
    	}
    	return 0;
    }
  • 相关阅读:
    EPANET头文件解读系列4——EPANET2.H
    EPANET头文件解读系列3——TOOLKIT.H
    EPANET头文件解读系列2——ENUMSTXT.H
    EPANET头文件解读系列1——TEXT.H
    ENUMSTXT.H中的指针数组
    main函数的参数
    函数指针与指针函数
    FMDB源码阅读
    17个提升iOS开发效率的必用工具
    UIKit性能调优实战讲解
  • 原文地址:https://www.cnblogs.com/demian/p/7389260.html
Copyright © 2011-2022 走看看