[Dijkstra] POJ 2253 Frogger | POJ 1797 Heavy Transportation | POJ 3268 Silver Cow Party

POJ 2253 Frogger | POJ 1797 Heavy Transportation | POJ 3268 Silver Cow Party

Dijkstra使用链式前向星实现的G=(V,E)

https://malash.me/200910/linked-forward-star/#comment-25291

由于MAXN上限太大开不了邻接矩阵,又由于卡时间用vector会TLE。

typedef long long LL;
typedef pair<LL,int> Pair;
const int MAX_P = 1000003;
const int INF = 0x3fffffff;
int P;// number of stops including CCS
int Q;// the number of bus lines

/* MLE: 1e12
 * int G[MAX_P][MAX_P];// 1-indexed
 */
/* TLE: >8000ms
 * vector<vector<Pair>> 
 * vector<Pair> GS[MAX_P];
 * vector<Pair> GD[MAX_P];
 * AC: 2188ms
 */
int dis[MAX_P];
int vis[MAX_P];
/*-----数据结构------*/
int head[MAX_P];	//记录以索引i为源点的边的链表的首条边在edge数组中的地址
int rhead[MAX_P];
struct Edge{
    int dst;
    int w;
    int next;
}edge[MAX_P*2];		// 双向Dijkstra中head和rhead共用cnt,若edge开为MAX_P会越界
/*-------add--------*/
int cnt=1;
void add(int head[],int S,int D,int w){
    edge[cnt].dst = D;
    edge[cnt].w = w;
    edge[cnt].next = head[S];
    head[S] = cnt++;
    /* 不能用++cnt, 只能用cnt++
     * 因为数组edge索引和head维护的当前链表头对应的边在edge数组 
     * 且head==0标志到达链表尾
     */
}
/*------------------*/

void dijkstra(int head[]){
    dis[1] = 0;
    priority_queue<Pair,vector<Pair>,greater<Pair>> Q;// min-heap
    Q.push(Pair(dis[1],1));
    while(!Q.empty()){
        Pair p = Q.top();
        Q.pop();
        int cur = p.second;
        if(vis[cur]) continue;
        vis[cur] = 1;
        for(int i=head[cur];i!=0;i=edge[i].next){
            int nxt = edge[i].dst;
            if(vis[nxt]) continue;
            int prc =edge[i].w;
            if(dis[cur] + prc < dis[nxt]){
                dis[nxt] = dis[cur] + prc;
                Q.push(Pair(dis[nxt],nxt));
            }
        }
    }
}

int main(){
    int N;
    scanf("%d",&N);
    for(int n=0;n<N;n++){
        fill(head,head+MAX_P,0);
        fill(rhead,rhead+MAX_P,0);
        cnt = 1;
        scanf("%d %d",&P,&Q);
        int S,D,price;
        for(int q=0;q<Q;q++){    
            scanf("%d %d %d",&S,&D,&price);
            add(head,S,D,price);
            add(rhead,D,S,price);
        }
        LL ans=0;
        fill(dis,dis+MAX_P,INF);
        fill(vis,vis+MAX_P,0);
        dijkstra(head);
        for(int i=1;i<=P;i++){
            ans += dis[i];
        }
        fill(dis,dis+MAX_P,INF);
        fill(vis,vis+MAX_P,0);
        dijkstra(rhead);
        for(int i=1;i<=P;i++){
            ans += dis[i];
        }
        
        // lld not ld
        printf("%lld
", ans);
    }
    return 0;
}

Dijkstra更新条件不同于最短路

POJ 2253 minmax distance;

POJ 1797 maxmin distance,距离初始化与minmax恰好相反。

下面只给出 POJ 2253 minmax题目AC解:

#include"stdio.h"
#include"string.h"
#include"math.h"
#include<vector>
#include<queue>
#include<functional>
#include<algorithm>
using namespace std;
typedef pair<int,int> Pair;
const int MAX_N = 203;
int N;
double G[MAX_N][MAX_N];
vector<Pair> pos;
int vis[MAX_N];
double frogd[MAX_N];
double EuDist(Pair p1,Pair p2){
    double x=p1.first-p2.first;
    double y=p1.second-p2.second;
    return sqrt(x*x+y*y);
}
void dijkstra(int s){
    frogd[s]=0;
    priority_queue<Pair,vector<Pair>,greater<Pair>> Q;
    Q.push(Pair(frogd[s],s));
    while(!Q.empty()){
        Pair p = Q.top();
        Q.pop();
        int cur = p.second;
        /* --------
        /* bfs标记vis的位置与push同时操作;
        /* dijkstra标记vis的操作在pop之后:
        /*   刚push进去的距离可能大于先前就在queue中的,
        /*   因此下一个加入vis集合的不一定是刚push进去的
           --------*/
        if(vis[cur]) continue;
        vis[cur]=1;
        double tmp_min=G[0][1];
        // int tmp_next;
        for(int j=0;j<N;j++){
            if(j==cur) continue;
            if(G[cur][j]==-1) continue;
            if(vis[j]) continue;
            if(max(frogd[cur],G[cur][j]) < frogd[j]) {
                frogd[j] = max(G[cur][j],frogd[cur]);
                Q.push(Pair(frogd[j],j));
            }
        }
    }
}
int main(){
    int t=0;
    while(scanf("%d",&N)!=EOF){
        t++;
        if(N==0) break;
        pos.clear();
        // do not use memset!
        fill(G[0],G[0]+MAX_N*MAX_N,-1);
        fill(vis,vis+MAX_N,0);
        fill(frogd,frogd+MAX_N,999999999);
        for(int n=0;n<N;n++){
            int x,y;
            scanf("%d %d",&x,&y);
            pos.push_back(Pair(x,y));//0-Freaddy, 1-Fiona
        }
        for(int i=0;i<N-1;i++){
            for(int j=i+1;j<N;j++){
                G[i][j]=G[j][i] = EuDist(pos[i],pos[j]);
            }
        }
        dijkstra(0);
        printf("Scenario #%d
", t);
        printf("Frog Distance = %.3f
", frogd[1]);
        printf("
");
    }
    return 0;
}

反向Dijkstra

POJ 3268 Silver Cow Party

求任一点和X的往返距离:每个点作为源进行一次dijkstra会TLE;事实上只用两遍Dijkstra(正向和反向)。

下面给反向DijsktraAC代码,其中数据初始化和正向相同,只有判断和更新条件略不同。

fill(disDst,disDst+MAX_N,0x3fffffff);

void dijkstraDst(int dst){
    disDst[dst]=0;
    priority_queue<Pair,vector<Pair>,greater<Pair>> Q;// min-heap
    Q.push(Pair(disDst[dst],dst));
    while(!Q.empty()){
        Pair p = Q.top();
        Q.pop();
        int cur = p.second;
        if(vis[cur]) continue;
        vis[cur] = 1;
        for(int i=1;i<=N;i++){
            if(G[i][cur]==-1) continue;
            if(disDst[cur]+G[i][cur] < disDst[i]){
                disDst[i] = disDst[cur]+G[i][cur];
                Q.push(Pair(disDst[i],i));
            }
        }
    }
}
原文地址:https://www.cnblogs.com/chengyh23/p/14585378.html