返回顶部

POJ - 1860 - Currency Exchange = SPFA

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

题意:有n种货币,m个相互兑换关系,初始拥有货币s共v元,求是否可以财富增加。

题意并不是说要走简单路径,他只是说了简单路径这个东西。

这个题暴露了对SPFA的认识不够。

首先这个SPFA是没有带优化的,玄学算法不需要优化。

一般的SPFA是节点入队次数超过n次就认为它存在负环,但是这里并不是这样判断(这里就是这样判断,WA是自己写错了,直接返回YES了),存在负环并不代表一定可以兑换回s(说不定在负环里只有0的汇率换回来s,导致白搞)但是这又是怎么阻止算法死循环的呢?

#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 = 105;
const int MAXM = 1005;

int top;
int head[MAXN];
struct Edge {
    int v, nxt;
    double w1, w2;
} edge[MAXM];

void init() {
    top = 0;
    memset(head, -1, sizeof(head));
}

void add_edge(int u, int v, double w1, double w2) {
    ++top;
    edge[top].v = v;
    edge[top].w1 = w1;
    edge[top].w2 = w2;
    edge[top].nxt = head[u];
    head[u] = top;
}

bool vis[MAXN];
double dis[MAXN];

queue<int>q;
bool spfa(int s, int n, double val) {
    memset(vis, 0, sizeof(vis));
    for(int i = 0; i < MAXN; ++i)
        dis[i] = 0;

    while(!q.empty())
        q.pop();

    q.push(s);
    vis[s] = 1;
    dis[s] = val;

    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;
            double w1 = edge[i].w1;
            double w2 = edge[i].w2;
            if(dis[u] < w2)
                continue;
            if(dis[v] < (dis[u] - w2)*w1) {
                dis[v] = (dis[u] - w2) * w1;
                if(dis[s] > val)
                    return 1;
                if(!vis[v]) {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    return 0;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n, m, s;
    double v;
    while(~scanf("%d%d%d%lf", &n, &m, &s, &v)) {
        if(n == 0)
            break;
        init();
        for(int i = 1; i <= m; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            double w1, w2;
            scanf("%lf%lf", &w1, &w2);
            add_edge(u, v, w1, w2);
            scanf("%lf%lf", &w1, &w2);
            add_edge(v, u, w1, w2);
        }
        if(spfa(s, n, v))
            puts("YES");
        else
            puts("NO");
    }
}

判断存在负环,则直接返回YES,因为反正会越滚越大的,终有一天是可以的。上面的代码为什么不会T我也不知道,可能是指数增长的确很快,最后很快就凑够手续费回去了。

#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 = 105;
const int MAXM = 1005;

int top;
int head[MAXN];
struct Edge {
    int v, nxt;
    double w1, w2;
} edge[MAXM];

void init() {
    top = 0;
    memset(head, -1, sizeof(head));
}

void add_edge(int u, int v, double w1, double w2) {
    ++top;
    edge[top].v = v;
    edge[top].w1 = w1;
    edge[top].w2 = w2;
    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, double val) {
    memset(vis, 0, sizeof(vis));
    memset(cnt, 0, sizeof(cnt));
    for(int i = 0; i < MAXN; ++i)
        dis[i] = 0;

    while(!q.empty())
        q.pop();

    q.push(s);
    vis[s] = 1;
    cnt[s] = 1;
    dis[s] = val;

    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;
            double w1 = edge[i].w1;
            double w2 = edge[i].w2;
            if(dis[v] < (dis[u] - w2)*w1) {
                dis[v] = (dis[u] - w2) * w1;
                if(!vis[v]) {
                    vis[v] = 1;
                    if(++cnt[v] <=  n)
                        q.push(v);
                    else
                        return 1;
                }
            }
        }
        if(dis[s] > val)
            return 1;
    }

    return dis[s] > val;
}



int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n, m, s;
    double v;
    while(~scanf("%d%d%d%lf", &n, &m, &s, &v)) {
        if(n == 0)
            break;
        init();
        for(int i = 1; i <= m; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            double w1, w2;
            scanf("%lf%lf", &w1, &w2);
            add_edge(u, v, w1, w2);
            scanf("%lf%lf", &w1, &w2);
            add_edge(v, u, w1, w2);
        }
        if(spfa(s, n, v))
            puts("YES");
        else
            puts("NO");
    }
}
posted @ 2019-10-22 22:14  Inko  阅读(89)  评论(0编辑  收藏  举报