pat甲级1087 多标准的dijkstra

首先用map解决城市名字到编号的映射。
题目给了最优路径的三个判断标准:
第一标准:边权累积最小。
第二标准:点权累积最大。
第三标准:平均点权最大。
下面判断这三个标准能否用dijkstra算法处理,
标准1:
已知 S -> PATH1 -> B -> D是第一标准最优,证明 S -> PATH1 -> B 也是最优。
假设存在 S -> PATH2 -> B 比它更短,那么 S -> PATH2 -> B -> D 比已知的最短路径更短
出现矛盾,所以不存在,得证。

标准2:同理可证。

标准3:已知 S -> PATH1 -> B -> D是第三标准最优,证明 S -> PATH1 -> B 也是最优。
PATH1上点的个数为 N1,点权累积为 W1
PATH2上点的个数为 N2,点权累积为 W2
那么已知最优路径到 D 的平均点权为 (WS+W1+WB+WD)/(N1+3)
到B的平均点权 (WS+W1+WB)/(N1+2)
假设存在 S -> PATH2 -> B 比它更优,即
(WS+W2+WB)/(N2+2) > (WS+W1+WB)/(N1+2)
证明 :(WS+W2+WB+WD)/(N2+3) > (WS+W1+WB+WD)/(N1+3)
//未完待续
在这里插入图片描述
标准3暂时不可证,稳妥的策略是用dijkstra处理前两个标准,找到多条路径,最后DFS找出第三标准最优的路径。如果三个标准全部一起dijkstra,pat测试点也能通过,但数据可能不全面。

#include <iostream>
#include <climits>
#include <string>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

const int maxv = 200;
const int INF = INT_MAX;

int N, K, S, D, mark=-1;
int v_weight[maxv];
int graph[maxv][maxv]={
    
    };
int d[maxv]; //第一标准:边权累积最小
bool confirmed[maxv]={
    
    };
int path_count[maxv]={
    
    }; //路径条数
int v_w_sum[maxv]={
    
    }; //第二标准:点权累积最大
vector<int> pre[maxv];
map<string, int> mp;

int f_ave=0;
vector<int> path, t_path;

int change(string a); //城市名到编号互转
void init(int s);
void dijkstra(int s); //以s为起点
void DFS(int v, int n); //访问到v,已经累积点权sum,点数n

int main(){
    
    
    string start;
    cin>>N>>K>>start;
    S = change(start); //起点
    v_weight[S]=0;
    for(int i=0; i<N-1; i++){
    
    
        string city;
        int w;
        cin>>city>>w;
        int c = change(city);
        v_weight[c] = w;
        if(city=="ROM") D = c; //终点
    }
    while(K--){
    
    
        string city1, city2;
        int cost;
        cin>>city1>>city2>>cost;
        int c1 = change(city1);
        int c2 = change(city2);
        graph[c1][c2] = graph[c2][c1] = cost;
    }
    dijkstra(S); //以第一、二标准找到最优路径
    DFS(D, 0); //在pre形成的倒置图上深度优先遍历,找第三标准最优
    cout<<path_count[D]<<' '<<d[D]<<' '<<v_w_sum[D]<<' '<<f_ave<<endl;
    int nm = path.size();
    for(int i=nm-1; i>=0; i--){
    
    
        map<string, int>::iterator it;
        for(it=mp.begin(); it!=mp.end(); it++){
    
    
            if(it->second==path[i]) break;
        }
        cout<<it->first;
        if(i>0) cout<<"->";
    }

    return 0;
}

int change(string a){
    
    
    map<string, int>::iterator it = mp.find(a);
    if(it!=mp.end()) return it->second;
    else{
    
    
        mark++;
        mp.insert(make_pair(a, mark));
        return mark;
    }
}

void init(int s){
    
    
    fill(d, d+N, INF);
    d[s] = 0;
    path_count[s] = 1;
    v_w_sum[s] = v_weight[s];
    return;
}

void dijkstra(int s){
    
    
    init(s);
    for(int k=0; k<N; k++){
    
    
        int u=-1, min_d=INF;
        for(int i=0; i<N; i++){
    
    
            if(!confirmed[i] && d[i]<min_d){
    
    
                u = i;
                min_d = d[i];
            }
        }
        if(u==-1) return;
        confirmed[u] = true;
        for(int j=0; j<N; j++){
    
    
            //u->j
            if(!confirmed[j] && graph[u][j]!=0){
    
    
                if(d[u]+graph[u][j]<d[j]){
    
    
                    //第一标准更优,要换路径
                    d[j] = d[u] + graph[u][j];
                    v_w_sum[j] = v_w_sum[u] + v_weight[j];
                    path_count[j] = path_count[u];
                    pre[j].clear();
                    pre[j].push_back(u);
                }
                else if(d[u]+graph[u][j]==d[j]){
    
    
                    path_count[j] += path_count[u];
                    if(v_w_sum[u]+v_weight[j]>v_w_sum[j]){
    
    
                        //第一标准相同,第二标准更优,要换路径,即清空pre再添加
                        v_w_sum[j] = v_w_sum[u] + v_weight[j];
                        pre[j].clear();
                        pre[j].push_back(u);
                    }
                    else if(v_w_sum[u]+v_weight[j]==v_w_sum[j]){
    
    
                        //一、二标准都相同,直接添加
                        pre[j].push_back(u);
                    }
                    //如果第一标准相同,第二标准更差,则路径更差,不记录
                }
                //如果第一标准更差,则路径更差,不记录
            }
        }
    }
    return;
}

void DFS(int v, int n){
    
    
    t_path.push_back(v);
    if(v==S){
    
    
        int a = v_w_sum[D]/n;
        if(a>f_ave){
    
    
            f_ave = a;
            path = t_path;
        }
        t_path.pop_back();
        return;
    }
    int t = pre[v].size();
    for(int i=0; i<t; i++){
    
    
        DFS(pre[v][i], n+1);
    }
    t_path.pop_back();
    return;
}

猜你喜欢

转载自blog.csdn.net/sinat_37517996/article/details/104545500
今日推荐