zoukankan      html  css  js  c++  java
  • POJ 3259 Wormholes(bellman_ford、Floyd、SPFA判断负环)

    POJ 3259 http://poj.org/problem?id=3259

    题意:

    农夫 FJ 有 N 块田地【编号 1...n】 (1<=N<=500)
    田地间有 M 条路径 【双向】(1<= M <= 2500)
    同时有 W 个孔洞,可以回到以前的一个时间点【单向】(1<= W <=200)
    问:FJ 是否能在田地中遇到以前的自己

    算法:bellman_ford 判断是否有负环

    思路:

    田地间的双向路径加边,权值为正
    孔洞间的单向路径加边,权值为负【可以回到以前】
    判断有向图是否存在负环
    因为如果存在了负数环,时间就会不停的减少,
    那么 FJ 就可以回到以前更远的地方,肯定能遇到以前的自己的

    bellman_ford

    #ifndef ONLINE_JUDGE
    #pragma warning(disalbe : 4996)
    #endif
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn = 510;
    const int maxw = 2500 * 2 + 200 + 10;
    const int inf = 10000;
    int d[maxn];
    int n, m;
    
    struct Edge {
    	int u, v;
    	int t;
    }edge[maxw];
    
    bool bellman_ford() {
    	for (int i = 1; i <= n; ++i) d[i] = inf;
    	d[1] = 0;//起点定为0
    
    	for (int i = 1; i < n; ++i) {
    		bool flag = true;
    		for (int j = 0; j < m; ++j) {
    			int u = edge[j].u;
    			int v = edge[j].v;
    			int t = edge[j].t;
    
    			if (d[v] > d[u] + t) {//松弛操作
    				d[v] = d[u] + t;
    				flag = false;
    			}
    		}
    		if (flag) return false;//如果当前轮不能松弛,直接判断没有负数环
    	}
    
    	for (int i = 0; i < m; ++i) 
    		if (d[edge[i].v] > d[edge[i].u] + edge[i].t)
    			return true;//如果仍然能够松弛则存在负环
    	
    	return false;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("in.txt", "r", stdin);
    	freopen("out.txt", "w", stdout);
    #endif // !ONLINE_JUDGE
    	int T;
    	int M, W;
    	scanf("%d", &T);
    	while (T--)
    	{
    		scanf("%d%d%d", &n, &M, &W);
    		m = 0;
    
    		int u, v, t;
    		for (int i = 1; i <= M; i++) //田地间的大路,加双边
    		{
    			scanf("%d%d%d", &u, &v, &t);
    			edge[m].u = u;
    			edge[m].v = v;
    			edge[m++].t = t;
    
    			edge[m].u = v;
    			edge[m].v = u;
    			edge[m++].t = t;
    		}
    
    		for (int i = 1; i <= W; i++) //孔洞,加单边
    		{
    			scanf("%d%d%d", &u, &v, &t);
    			edge[m].u = u;
    			edge[m].v = v;
    			edge[m++].t = -t;
    		}
    
    		if (bellman_ford()) printf("YES\n"); //存在负数环
    		else printf("NO\n");
    	}
    #ifndef ONLINE_JUDGE
    	fclose(stdin);
    	fclose(stdout);
    	system("out.txt");
    #endif // !ONLINE_JUDGE
    	return 0;
    }
    

    Floyd

    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    int n, m, W;//教室、普通走廊、回溯
    const int inf = 0x3f3f3f3f, maxn = 510;
    int g[maxn][maxn];
    
    bool floyd() {
    	for (int k = 1; k <= n; ++k)
    		for (int i = 1; i <= n; ++i) {
    			for (int j = 1; j <= n; ++j)
    				if (g[i][j] > g[i][k] + g[k][j])
    					g[i][j] = g[i][k] + g[k][j];
    			if (g[i][i] < 0)return true;//存在负环
    		}
    	return false;
    }
    
    int main() {
    	//freopen("in.txt","r",stdin);
    	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    	int t; cin >> t; while (t--) {
    		cin >> n >> m >> W;
    		for (int i = 1; i <= n; ++i)
    			for (int j = 1; j <= n; ++j)
    				g[i][j] = inf;
    		for (int i = 0; i <= n; ++i)g[i][i] = 0;
    
    		int u, v, w;
    		for (int i = 0; i < m; ++i)
    			cin >> u >> v >> w, g[u][v] = g[v][u] = min(g[u][v],w);
    		for (int i = 0; i < W; ++i)
    			cin >> u >> v >> w, g[u][v] = -w;
    		cout << (floyd() ? "YES" : "NO" )<< endl;
    		
    	}
    }
    

    SPFA

    //kuangbin 的板子确实挺漂亮的
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    typedef long long ll;
    int n;
    const int MAXN = 505, 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) {
        memset(vis, false, sizeof vis);
        memset(cnt, 0, sizeof cnt);
        memset(dist, INF, sizeof dist);
        queue<int> que;
        que.push(start);
        ++cnt[start];
        dist[start] = 0;
        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 true;
                    }
                }
            }
        }
        return false;
    }
    
    int main() {
        int f, m, W;
        scanf("%d", &f);
        while (f--) {
            scanf("%d%d%d", &n, &m, &W);
            int u, v, w;
            for (int i = 0; i < m; ++i) {
                scanf("%d%d%d", &u, &v, &w);
                addedge(u, v, w);
                addedge(v, u, w);
            }
            for (int i = 0; i < W; ++i) {
                scanf("%d%d%d", &u, &v, &w);
                addedge(u, v, -w);
            }
    
            printf("%s\n", SPFA(1) ? "YES" : "NO");
            for (int i = 1; i <= n; ++i)
                E[i].clear();
        }
        return 0;
    }
    

    三种方法AC以后发现BF竟然时间最短

  • 相关阅读:
    微信转发或分享朋友圈带缩略图、标题和描述的实现方法
    apache一个IP多个站点的配置方法
    微信网页扫码登录的实现
    laravel take(3) 读取最近三条信息
    微信卡劵、微信卡包,必须是认证订阅号或认证服务号
    CSS3 去除苹果浏览器按钮input[type="submit"]和input[type="reset"]的默认样式
    使用laravel5.4结合easywechat进行微信开发--基本配置
    Class 'QrCode' not found ? 和 laravel 生成二维码接口(Simple QrCod)
    windows redis的启动 和 Laravel中Redis的使用
    改变checkbox的默认样式
  • 原文地址:https://www.cnblogs.com/RioTian/p/12913289.html
Copyright © 2011-2022 走看看