• POJ


    http://poj.org/problem?id=2240

    给定几种货币,和他们之间的汇率,求是不是有一个方法使得货币兑换一圈之后变多。

    总而言之就是是否存在回路,路径上的权值的积大于1。

    这个描述看起来就很SPFA,假如把路径的权值的积取负对数,就是问是否有负环。

    直接上SPFA,果然很慢,要844ms(可能是常数不好)。

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<map>
    #include<set>
    #include<stack>
    #include<string>
    #include<queue>
    #include<vector>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 35;
    const int MAXM = 1005;
    
    int top;
    int head[MAXN];
    struct Edge {
        int v, nxt;
        double w;
    } edge[MAXM];
    
    void init() {
        top = 0;
        memset(head, -1, sizeof(head));
    }
    
    void add_edge(int u, int v, double w) {
        ++top;
        edge[top].v = v;
        edge[top].w = w;
        edge[top].nxt = head[u];
        head[u] = top;
    }
    
    bool vis[MAXN];
    int cnt[MAXN];
    double dis[MAXN];
    
    queue<int>q;
    bool spfa(int s, int n) {
        memset(vis, 0, sizeof(vis));
        memset(cnt, 0, sizeof(cnt));
        for(int i = 0; i < MAXN; ++i)
            dis[i] = 1e18;
    
        while(!q.empty())
            q.pop();
        q.push(s);
        vis[s] = 1;
        cnt[s] = 1;
        dis[s] = 0;
    
        while(!q.empty()) {
            int u = q.front();
            q.pop();
            vis[u] = 0;
            for(int i = head[u]; i != -1; i = edge[i].nxt) {
                int v = edge[i].v;
                if(dis[v] > dis[u] + edge[i].w) {
                    dis[v] = dis[u] + edge[i].w;
                    if(!vis[v]) {
                        vis[v] = 1;
                        q.push(v);
                        if(++cnt[v] > n)
                            return 0;
                    }
                }
            }
        }
        return 1;
    }
    
    map<string, int> M;
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        int n, m, ti = 0;
        while(~scanf("%d", &n)) {
            if(n == 0)
                break;
            M.clear();
            for(int i = 1; i <= n; ++i) {
                string s;
                cin >> s;
                M[s] = i;
            }
            scanf("%d", &m);
            init();
            while(m--) {
                string s;
                cin >> s;
                int u = M[s];
                double w;
                cin >> w;
                w = -log(w);
                cin >> s;
                int v = M[s];
                add_edge(u, v, w);
            }
    
            bool ans = 1;
            for(int i = 1; i <= n; ++i) {
                ans &= spfa(i, n);
                if(ans == 0)
                    break;
            }
    
            printf("Case %d: ", ++ti);
            puts(ans == 0 ? "Yes" : "No");
        }
    }
    

    我记得SPFA也是单源最短路来的,会不会有更好的办法呢?

    Floyd也可以,不过没有快多少。

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<map>
    #include<set>
    #include<stack>
    #include<string>
    #include<queue>
    #include<vector>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 35;
    double dis[MAXN][MAXN];
    
    map<string, int> M;
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        int n, m, ti = 0;
        while(~scanf("%d", &n)) {
            if(n == 0)
                break;
            M.clear();
            for(int i = 1; i <= n; ++i) {
                string s;
                cin >> s;
                M[s] = i;
            }
            scanf("%d", &m);
            for(int i = 1; i <= n; ++i) {
                for(int j = 1; j <= n; ++j) {
                    dis[i][j] = 0;
                    if(i == j)
                        dis[i][j] = 1;
                }
            }
            while(m--) {
                string s;
                cin >> s;
                int u = M[s];
                double w;
                cin >> w;
                cin >> s;
                int v = M[s];
                dis[u][v] = w;
            }
    
            for(int k = 1; k <= n; ++k) {
                for(int i = 1; i <= n; ++i) {
                    for(int j = 1; j <= n; ++j)
                        dis[i][j] = max(dis[i][j], dis[i][k] * dis[k][j]);
                }
            }
    
            bool ans = 1;
            for(int i = 1; i <= n; ++i) {
                if(dis[i][i] > 1) {
                    ans = 0;
                    break;
                }
            }
    
            printf("Case %d: ", ++ti);
            puts(ans == 0 ? "Yes" : "No");
        }
    }
    
  • 相关阅读:
    C加加学习之路 1——开始
    哈夫曼树C++实现详解
    Linux常用命令
    Accp第二章:基础知识
    第一章Accp 8.0
    泛型集合
    深入C#数据类型
    初始wondows系统
    深入.NET框架
    二至十五章总结
  • 原文地址:https://www.cnblogs.com/Inko/p/11712699.html
Copyright © 2020-2023  润新知