[SPFA (Bellman Ford)] POJ 1860 Currency Exchange | POJ 3259 Wormholes | LightOJ 1074 Extended Traffic

POJ 1860 Currency Exchange | POJ 3259 Wormholes | LightOJ 1074 Extended Traffic

SPFA (Bellman Ford)

POJ 1860 Currency Exchange

#include"stdio.h"
#include"string.h"
#include"math.h"
#include<vector>
#include<queue>
#include<functional>
#include<algorithm>
using namespace std;
typedef pair<double,double> Pair;
typedef pair<double,int> PairDI;
const int MAX_NM=103;
const int MAX_V=1003;
int N;// n currency, 1-indexed
int M;// n ExPoints
int S;
double V;

Pair G[MAX_NM][MAX_NM];
double dis[MAX_NM];
bool vis[MAX_NM];
int cnt[MAX_NM];
bool SPFA(int S){
    dis[S]=V;
    priority_queue<PairDI> Q;// max heap
    Q.push(PairDI(dis[S],S));
    vis[S]=true;
    ++cnt[S];
    while(!Q.empty()){
        PairDI p = Q.top();
        Q.pop();
        int cur = p.second;
        vis[cur]=false;
        for(int i=1;i<=N;i++){
            if(G[cur][i].first==0.0) continue;// no path
            double r = G[cur][i].first;
            double c = G[cur][i].second;
            if((dis[cur]-c)*r > dis[i]){
                // printf("%d %d
", cur,i);
                dis[i] = (dis[cur]-c)*r;
                if(!vis[cur]){
                    Q.push(Pair(dis[i],i));
                    vis[i]=true;
                    if(++cnt[i] > N-1) return true;
                }
            }
        }
    }
    return false;// 不存在“负权环”
}

int main(){
    fill(G[0],G[0]+MAX_NM*MAX_NM,Pair(0,0));
    fill(dis,dis+MAX_NM,0);
    fill(vis,vis+MAX_NM,false);
    fill(cnt,cnt+MAX_NM,0);
    scanf("%d%d%d%lf",&N,&M,&S,&V);
    for(int m=0;m<M;m++){
        int A,B;
        double R_AB,C_AB,R_BA,C_BA;
        scanf("%d %d %lf %lf%lf %lf",&A,&B,&R_AB,&C_AB,&R_BA,&C_BA);
        G[A][B] = Pair(R_AB,C_AB);
        G[B][A] = Pair(R_BA,C_BA);
    }
    if(SPFA(S)) printf("YES
");
    else printf("NO
");
    return 0;
}

POJ 3259 Wormholes

  • 判断是否存在负环(从任源点出发),每个节点作源进行SPFA显然会TLE。
  • 只进行一次单源SPFA:
    • 添加辅助顶点C,有向边S->C,有向边C->v (其中v∈V - {S} )。即可只进行一次单源SPFA;
    • 同时防止因添加顶点C引入了负环,因此:
    • 这些有向边的权重ω要足够大,满足2ω>MAX_NW(负权边的绝对值的最大值)。
/* #include 省略 */
typedef pair<int,int> Pair;
const int MAX_N = 503;
int N;// fields, 1~500
int M;// paths
int W;// wormholes
int G[MAX_N][MAX_N];
int dis[MAX_N];
bool vis[MAX_N];
int cnt[MAX_N];
bool SPFA(int s){
    dis[s]=0;
    priority_queue<Pair,vector<Pair>,greater<Pair>> Q;// min heap
    Q.push(Pair(dis[s],s));
    vis[s]=true;
    cnt[s]++;
    while(!Q.empty()){
        Pair p = Q.top();
        Q.pop();
        int cur = p.second;
        vis[cur]=false;
        for(int i=1;i<=N+1;i++){
            if(G[cur][i]>10000) continue;
            if(dis[cur]+G[cur][i] < dis[i]){
                // printf("%d %d
", cur,i);
                dis[i] = dis[cur]+G[cur][i];
                if(!vis[cur]){
                    Q.push(Pair(dis[i],i));
                    vis[i]=true;
                    if(++cnt[i] > N+1-1) return true;
                }
            }
        }
    }
    return false;
}

int main(){
    int F;
    scanf("%d",&F);
    for(int f=0;f<F;f++){
        fill(G[0],G[0]+MAX_N*MAX_N,20000);
        scanf("%d %d %d",&N,&M,&W);
        for(int m=0;m<M;m++){// bidirectional, might be connected by more than one path
            int S,E,T;
            scanf("%d %d %d",&S,&E,&T);
            G[S][E] = G[E][S] = (G[S][E]>10000)? T : min(G[S][E],T);
        }
        for(int w=0;w<W;w++){// one-way
            int S,E,T;
            scanf("%d %d %d",&S,&E,&T);
            G[S][E] = (G[S][E]>10000)? (-1)*T : min(G[S][E],(-1)*T);
        }
        // 辅助节点到各节点的边权设置
        G[1][N+1]=10000;
        for(int i=2;i<=N;i++) G[N+1][i]=10000;
        
        fill(dis,dis+MAX_N,999999999);
        fill(vis,vis+MAX_N,false);
        fill(cnt,cnt+MAX_N,0);
        if(SPFA(1)) printf("YES
");
        else printf("NO
");
    }
    return 0;
}

LightOJ 1074 Extended Traffic

相较于判断是否存在负环,不同之处在于

typedef pair<int,int> Pair;
const int INF=0x3fffffff;
const int MAX_N=203;
int N;// n junction
int M;// n roads
int Q;// n queries
int bsns[MAX_N];
int G[MAX_N][MAX_N];
int dis[MAX_N];
int vis[MAX_N];
int cnt[MAX_N];
int cube(int src,int dst){// how to deal with negative val
    int tmp = bsns[dst]-bsns[src];
    return tmp*tmp*tmp;
}
void spfa(){
    dis[1]=0;
    priority_queue<Pair,vector<Pair>,greater<Pair> > Q;// min heap
    Q.push(Pair(dis[1],1));
    vis[1]=1;
    cnt[1]++;
    while(!Q.empty()){
        Pair p = Q.top();
        Q.pop();
        int cur = p.second;
        vis[cur]=0;
        for(int i=1;i<=N;i++){
            if(G[cur][i]==0) continue;
            if(dis[cur] + cube(cur,i) < dis[i]){
                dis[i] = dis[cur] + cube(cur,i);
                if(!vis[i]) {
                    // 当发现有负环时不应return,而是continue
                    // 应使负环可达的所有点的cnt都 > N-1
                    if(cnt[i]++ > N-1) continue;
                    Q.push(Pair(dis[i],i));
                    vis[i]=1;
                    // 判断是否存在负环的模板做法:
                    // if(cnt[i]++ > N-1) return;
                }
            }
        }
    }
    return;
}
int main(){
    int T;
    scanf("%d",&T);
    for(int t=1;t<=T;t++){
        fill(G[0],G[0]+MAX_N*MAX_N,0);fill(dis,dis+MAX_N,INF);fill(vis,vis+MAX_N,0);
        fill(cnt,cnt+MAX_N,0);
        scanf("%d",&N);
        for(int n=1;n<=N;n++) scanf("%d",&bsns[n]);
        scanf("%d",&M);
        for(int m=1;m<=M;m++){
            int src,dst; scanf("%d %d",&src,&dst);
            G[src][dst]=1;// uni-directional
        }
        spfa();
        printf("Case %d:
", t);
        scanf("%d",&Q);
        for(int q=0;q<Q;q++){
            int x; scanf("%d",&x);
            // total earning less than 3 or unreachable
            // 事实上述题目给的要求比较隐晦,没直接说负环输出“?”
            // 若存在负环,dis无定义(-∞),因此判断条件还要加上:cnt[x]>N-1
            if(dis[x]<3 || dis[x]==INF ||cnt[x]>N-1) printf("?
");
            else printf("%d
", dis[x]);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/chengyh23/p/14585366.html