pat 1087

1087 All Roads Lead to Rome (30分)

 

Indeed there are many different tourist routes from our city to Rome. You are supposed to find your clients the route with the least cost while gaining the most happiness.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers N (2), the number of cities, and K, the total number of routes between pairs of cities; followed by the name of the starting city. The next N?1 lines each gives the name of a city and an integer that represents the happiness one can gain from that city, except the starting city. Then K lines follow, each describes a route between two cities in the format City1 City2 Cost. Here the name of a city is a string of 3 capital English letters, and the destination is always ROM which represents Rome.

Output Specification:

For each test case, we are supposed to find the route with the least cost. If such a route is not unique, the one with the maximum happiness will be recommanded. If such a route is still not unique, then we output the one with the maximum average happiness -- it is guaranteed by the judge that such a solution exists and is unique.

Hence in the first line of output, you must print 4 numbers: the number of different routes with the least cost, the cost, the happiness, and the average happiness (take the integer part only) of the recommanded route. Then in the next line, you are supposed to print the route in the format City1->City2->...->ROM.

Sample Input:

6 7 HZH
ROM 100
PKN 40
GDN 55
PRS 95
BLN 80
ROM GDN 1
BLN ROM 1
HZH PKN 1
PRS ROM 2
BLN HZH 2
PKN GDN 1
HZH PRS 1

Sample Output:

3 3 195 97
HZH->PRS->ROM

 

题意:给定一张图以及初始顶点,要求求出从初始顶点到ROM的最短距离,如果有多条路径具有相同的最短路径,则选取路径中点权值之和最大的那条,如果这样的路径仍不唯一,选取平均点权值最大的那一条(不包含初始顶点)。最后输出最短路径的条数、最短距离、最大点权值之和、所选路径的平均点权,并打印出路径。

思路:

  两种做法,其一我参考的柳神的代码,dijkstra+dfs,首先dijkstra求出从初始顶点到罗马的所有最短路径,用一个二维数组存起来(因为最短路径不止一条,这里我用的vector 数组),得到所有最短路径的path数组之和用dfs算法遍历,求得的path数组相当于是一个有向图,并且是原图的一个子图(这里体会下为什么是有向图,这一点是写dfs的一个关键点)。然后通过dfs算法,从ROM这个顶点递归的求出所有最短路径,定义几个全局变量表示最大点权之和、平均点权,在dfs内部,一旦递归的结点到达了起始顶点,便求出这条递归路径上的点权之和、平均点权,与全局变量比较,如果更符合题目条件,则替代之,并将这条路径作为暂时的答案(继续递归可能会有更优的答案)。最短距离是在用dijkstra算法的时候就求出来了的,之后按照题目要求输出这些信息即可。(个人感觉这种方法不如直接用dfs算法来得简介,dfs算法可以解决图中两个顶点之间的 最短距离问题,很多书上只讲了dijkstra、floyed和bfs算法来 解决最短路径问题,这里没有学过dfs求 最短路径的同学可以参考这篇博客

代码如下:dijkstra+dfs

#include<cstdio>
#include<map>
#include<string>
#include<iostream>
#include<vector>
#define inf 999999
using namespace std;
int n,k;
string beg;
int happys[205];
int G[205][205];
map<string,int> m;
map<int,string> m2;
int index=0;
bool visited[205]={false};
vector<int> path[205];
int dist[205];
int findMin(){
    int min=-1;
    int minValue=inf;
    for(int i=0;i<n;i++){
        if(visited[i]==false)
        if(dist[i]<minValue){
            min=i;
            minValue=dist[i];
        }
    }
    return min;
}
void dijkstra(int v){
    visited[v]=true;
    for(int i=0;i<n;i++){
        dist[i]=G[v][i];
        if(dist[i]<inf)
            path[i].push_back(v);
    }
    dist[v]=0;
    path[v].push_back(-1);
    while(1){
        int s=findMin();
        if(s==-1)
            break;
        visited[s]=true;
        for(int i=0;i<n;i++){
            if(visited[i]==false){
                if(dist[s]+G[s][i]<dist[i]){
                    dist[i]=dist[s]+G[s][i];
                    path[i].clear();
                    path[i].push_back(s);
                }
                else if(dist[i]==dist[s]+G[s][i]){
                    path[i].push_back(s);
                }
                    
            }
        }
    }
}
vector<int> temppath;
int maxhappy=0;
double averhapp=0;
int cnt=0;
vector<int> ans;
void dfs(int v){
    temppath.push_back(v);
    if(v==0){
        cnt++;
        int value=0;
        double temphapp=0;
        
        for(int i=0;i<temppath.size();i++){
            value+=happys[temppath[i]];
        }
        temphapp=value*1.0/(temppath.size()-1);
        if(value>maxhappy){
            maxhappy=value;
            averhapp=temphapp;
            ans=temppath;
        }
        else if(value==maxhappy&&averhapp<temphapp){
            averhapp=temphapp;
            ans=temppath;
        }
        temppath.pop_back();
        return;
    }
    for(int i=0;i<path[v].size();i++){
        dfs(path[v][i]);
    }
    temppath.pop_back();
} 
int main(){
    fill(G[0],G[0]+205*205,inf);
    beg.resize(5);
    scanf("%d%d%s",&n,&k,&beg[0]);
    m[beg]=0;
    m2[0]=beg;
    string temp;
    int hap;
    for(int i=1;i<n;i++){
        cin>>temp>>hap;
        m[temp]=i;
        m2[i]=temp;
        happys[i]=hap;
    }
    string sa,sb;
    int dis;
    for(int i=0;i<k;i++){
        cin>>sa>>sb>>dis;
        G[m[sa]][m[sb]]=dis;
        G[m[sb]][m[sa]]=dis;
    }
    dijkstra(0);
    int rom=m["ROM"];
    dfs(rom);
    printf("%d %d %d %d\n",cnt,dist[rom],maxhappy,(int)averhapp);
    for(int i=ans.size()-1;i>=0;i--){
        if(i==ans.size()-1)
            printf("%s",m2[ans[i]].c_str());
        else
            printf("->%s",m2[ans[i]].c_str());
    }
        
    return 0;
}

 

  方法二是直接使用dfs算法,不懂为什么可以直接用dfs请参考上面链接的那篇博客。思路跟dijkstra+dfs的方法差不多,只是求最短距离是在dfs算法内部解决的,需要注意的是这里的dfs和上面那种算法中用到的dfs算法略有差别,因为在该算法中,dfs遍历的是整张图(我们知道在遍历的时候需要设置visited数组记录某个顶点是否以及遍历过了),在这里遍历的时候只能往前(从罗马查找起始点的方向),不能往后,因此在求某个顶点邻接点依次用dfs的时候,在这个for循环之前要先把该顶点的visited数组设置为1,在for循环之后需要把它改回0,这是因为在上一层递归的时候仍然可能存在到这个点的路径。而dijkstra+dfs算法中的dfs不需要关注这一点,这是因为上面说过了dfs的是一张原图的有向子图,path数组中根本不存在往反方向的边。

代码如下:

#include<cstdio>
#include<unordered_map>
#include<vector>
using namespace std;
int n,k;
char start[5];
int weight[205];
int G[205][205]={0};
unordered_map<string,int> m;
unordered_map<int,string> m2;
vector<int> temppath,path;
int minDist=999999;
int maxHappy=0;
double averHappy=0;
int visited[205]={0};
int cnt=0;
void dfs(int v,int dist,int happy,int aver){
    happy+=weight[v];
    temppath.push_back(v);
    if(v==0){
        int value=0;
        for(int i=0;i<temppath.size();i++){
            value+=weight[temppath[i]];
        }
        if(minDist>dist){
            minDist=dist;
            maxHappy=value;
            averHappy=value*1.0/(temppath.size()-1);
            path=temppath;
            cnt=1;
        }
        else if(minDist==dist&&value>maxHappy){
            maxHappy=value;
            averHappy=value*1.0/(temppath.size()-1);
            path=temppath;
            cnt++;
        }
        else if(minDist==dist&&value==maxHappy&&averHappy<(value*1.0/(temppath.size()-1))){
            averHappy=value*1.0/(temppath.size()-1);
            path=temppath;
            cnt++;
        }
        else if(minDist==dist)
            cnt++;
        temppath.pop_back();
        return;
    }
    visited[v]=1;
    for(int i=0;i<n;i++){
        if(G[v][i]!=0&&visited[i]==0){
            dfs(i,dist+G[v][i],happy,aver);
        }
    }
    temppath.pop_back();
    visited[v]=0;
}
int main(){
    scanf("%d%d%s",&n,&k,start);
    m[start]=0;
    m2[0]=start;
    weight[0]=0;
    char temp[5];
    int w;
    for(int i=1;i<n;i++){
        scanf("%s%d",temp,&w);
        m[temp]=i;
        m2[i]=temp;
        weight[i]=w;
    }
    char temp2[5];
    int dis;
    for(int i=0;i<k;i++){
        scanf("%s %s %d",temp,temp2,&dis);
        G[m[temp]][m[temp2]]=G[m[temp2]][m[temp]]=dis;
    }
    int rom=m["ROM"];
    int dist=0;
    int happy=0;
    int aver=0;
    dfs(rom,dist,happy,aver);
    printf("%d %d %d %d\n",cnt,minDist,maxHappy,(int)averHappy);
    for(int i=path.size()-1;i>=0;i--){
        if(i!=path.size()-1)
            printf("->%s",m2[path[i]].c_str());
        else 
            printf("%s",m2[path[i]].c_str());
    }
    return 0;
} 

 

   综上所述,我还是觉得dfs的代码量比较友好,但是有时候非得用dijkstra,因为dfs只能求两点之间最短路径,而不能求单源最短路径。

posted @ 2020-07-23 14:02  9761滴  阅读(137)  评论(0编辑  收藏  举报