L3-011 直捣黄龙 (30 分)

发布时间:2019年03月23日 阅读:330 次

PAT L3-011 直捣黄龙


 

L3-011 直捣黄龙 (30 分)

本题是一部战争大片 —— 你需要从己方大本营出发,一路攻城略地杀到敌方大本营。首先时间就是生命,所以你必须选择合适的路径,以最快的速度占领敌方大本营。当这样的路径不唯一时,要求选择可以沿途解放最多城镇的路径。若这样的路径也不唯一,则选择可以有效杀伤最多敌军的路径。

输入格式:

输入第一行给出 2 个正整数 N(2 ≤ N ≤ 200,城镇总数)和 K(城镇间道路条数),以及己方大本营和敌方大本营的代号。随后 N-1 行,每行给出除了己方大本营外的一个城镇的代号和驻守的敌军数量,其间以空格分隔。再后面有 K 行,每行按格式城镇1 城镇2 距离给出两个城镇之间道路的长度。这里设每个城镇(包括双方大本营)的代号是由 3 个大写英文字母组成的字符串。

输出格式:

按照题目要求找到最合适的进攻路径(题目保证速度最快、解放最多、杀伤最强的路径是唯一的),并在第一行按照格式己方大本营->城镇1->...->敌方大本营输出。第二行顺序输出最快进攻路径的条数、最短进攻距离、歼敌总数,其间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:

10 12 PAT DBYDBY 100PTA 20PDS 90PMS 40TAP 50ATP 200LNN 80LAO 30LON 70PAT PTA 10PAT PMS 10PAT ATP 20PAT LNN 10LNN LAO 10LAO LON 10LON DBY 10PMS TAP 10TAP DBY 10DBY PDS 10PDS PTA 10DBY ATP 10

输出样例:

PAT->PTA->PDS->DBY3 30 210

作者: 陈越

单位: 浙江大学

时间限制: 150 ms

内存限制: 64 MB

代码长度限制: 16 KB

 

 

 my code:  因为Num数组记录出错 导致少了一个记录点 改了就a了

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int inf  =0x3f3f3f3f;
map<string,int>mp;
map<int,string>name;
int dist[600],vis[600];
int dist2[600],dist3[600],n;
int tu[600][600],w[600][600];
int cnt =0;
int Kill[600];
int id(string h){
  if(mp.count(h)){
    return mp[h];
  }
  else{

    mp[h] = cnt++;
    name[cnt-1] = h;
    return cnt-1;
  }
}
int pre[600],Num[600];
void dijkstra(int s){

  memset(dist,inf,sizeof dist);
  memset(dist2,0,sizeof dist2);
  memset(dist3,0,sizeof dist3);
  memset(Num,0,sizeof Num);
  memset(vis,0,sizeof vis);
  memset(pre,-1,sizeof pre);
  dist[s] =0;
  dist2[s] =0;
  dist3[s] = Kill[s];
  Num[s] = 1;
  while(1){

    int x =-1,Min =inf;
    for(int i=0;i<n;i++)
    {
        if(!vis[i]&&Min>dist[i]){

            Min  = dist[i];
            x  =i;
        }
    }
    if(x==-1)break;
    vis[x] = 1;
    for(int i=0;i<n;i++){

        if(!vis[i]){

            if(dist[i]>dist[x]+tu[x][i]){

                dist[i] = dist[x]+tu[x][i];
             //   dist2[i] = dist2[x]+w[x][i];
             dist2[i] = dist2[x]+1;
             dist3[i] = dist3[x]+Kill[x];
             Num[i] = Num[x];
                 pre[i] = x;
            }
            else if(dist[i]==dist[x]+tu[x][i]){
//                if(dist2[i]>dist2[x]+w[x][i]){
//
//                   dist2[i] = dist2[x]+w[x][i];
//                }
                 Num[i] +=Num[x];
                if(dist2[i]<dist2[x]+1){

                    dist2[i] = dist2[x]+1;
                    dist3[i] = dist3[x]+Kill[x];
                    pre[i] = x;
                }
                else if(dist2[i]==dist2[x]+1){

                    if(dist3[i]<dist3[x]+Kill[x]){

                        dist3[i] = dist3[x]+Kill[x];
                        pre[i] = x;
                    }
                }


            }
        }
    }

  }
}


int main()
{

    int m,s,d;
    cin>>n>>m;
    string ss,dd;
    cin>>ss>>dd;
    s = id(ss);
    d = id(dd);
    for(int i=0;i<=n;i++){

          for(int j=0;j<=n;j++){

            if(i==j)continue;
            tu[i][j] = inf;
            w[i][j]=inf;
          }
    }
    int u,v,l,ww;
    for(int i=1;i<=n-1;i++){

        string s;
        int num;
        cin>>s>>num;
        int id1  =id(s);
        Kill[id1] = num;
    }
    for(int i=1;i<=m;i++){

        string s1,s2;
        int num;
        cin>>s1>>s2>>num;
        int i1 = id(s1);
        int i2 = id(s2);
        tu[i1][i2]= tu[i2][i1] = min(num,tu[i2][i1]);
    }
//    for(int i=1;i<=m;i++){
//
//        scanf("%d%d%d%d",&u,&v,&l,&ww);
//        tu[u][v] = tu[v][u] = l;
//        w[u][v]= w[v][u] = ww;
//    }
    dijkstra(s);
    int pp  = d;
    int ans =0;
    stack<string>aa;
    while(pp!=-1){

       ans+=Kill[pp];
       aa.push(name[pp]);
       pp = pre[pp];
    }
    int top  =1;
    while(!aa.empty()){

        string k;
        k = aa.top();
        aa.pop();
        if(top)top=0;
        else printf("->");
        cout<<k;
    }
    printf("\n");
    cout<<Num[d]<<" "<<dist[d]<<" "<<ans<<endl;
    //cout<<dist[d]<<" "<<dist2[d]<<endl;



    return 0;
}


这道题是基础的最短路算法加一些限制条件,代码用的SPFA算法。输入数据的城市编号是字符串,用map映射成整数就可以去存边,跑最短路了。

求最短路时

if(dist[v]>dist[u]+fee) 这时就直接更新到城市v的最短距离了;

path[v]=u;    记录到城市v的最短路径中v的上一个城市是谁;

town[v]=town[u]+1;    town数组记录到城市v的最短路中最多可以解放多少城市(就是整个路径经过多少个城市);

shadi[v]=shadi[u]+army[v];    数组shadi记录通过最短路到城市v最多可以杀敌多少;

lushu[v]=lushu[u];    数组lushu记录最短距离相同的路径有几条;

开始WA了无数发就是因为不知道咋想的把最短路被更新时lushu[v]从1开始重新计数,写了个lushu[v]=1,然后错错错

 

#include <bits/stdc++.h>
#define INF 1234123411
using namespace std;
 
int N,M,K,cnt,shu,zuiduan;
int army[210];//army[i]记录城市i有多少敌军
int dist[210];//记录从源点到每个城市的最短距离
int path[210];//path[i]=j记录到城市i的最短路径中,上一步是从j走到i的
int town[210];//town[i]记录通过最短路到城市i时,沿途最多解放了多少城市(其实就是经过了多少)
int shadi[210];//shadi[i]表示通过最短路到城市i时,一共杀敌多少
int res[210];//输出路径时用到
int lushu[210];//最短路可能不止一条,lushu[i]表示到城市i最短距离相同的路径有几条
bool vis[210];
vector<struct data>G[210];//存边建图
map<string,int>Q;//输入的城市编号是字符串,映射成整数
map<int,string>P;
string tou,wei,ch,s1,s2;
 
struct data
{
    int to;
    int cost;
};
 
void SPFA(int s)
{
    for(int i=0;i<210;i++)dist[i]=INF;
    dist[s]=0;
    lushu[s]=1;
    queue<int> qwq;
    qwq.push(s);
    vis[s]=1;
 
    while(!qwq.empty())
    {
        int u=qwq.front();
        qwq.pop();
        vis[u]=0;
 
        for(int i=0;i<int(G[u].size());i++)
        {
            bool sign=false;
            int v=G[u][i].to;
            int fee=G[u][i].cost;
            if(dist[v]>dist[u]+fee)
            {
                sign=true;
                dist[v]=dist[u]+fee;//更新到v的最短距离
                path[v]=u;//到v的最短路中上一步是从城市u走到v的
                town[v]=town[u]+1;//到v最多可以解放的城市数量
                shadi[v]=shadi[u]+army[v];//到v最多可以杀敌的数量
                lushu[v]=lushu[u];//既然现在更新的最短路是上一步是从u走到v的,
                //那么到u的最短路有几条,到v的最短路也有几条
                //就是在这里一开始简单的写成lushu[v]=1;导致30分只得25分
            }
            else if(dist[v]==dist[u]+fee)
            {
                if(town[v]<town[u]+1)
                {
                    path[v]=u;
                    town[v]=town[u]+1;
                    shadi[v]=shadi[u]+army[v];
                }
                else if(town[v]==town[u]+1)
                {
                    if(shadi[v]<shadi[u]+army[v])
                    {
                        path[v]=u;
                        shadi[v]=shadi[u]+army[v];
                    }
                }
                lushu[v]+=lushu[u];//在else if这部分内容如果执行的话说明从源点经过u到v的距离
                //不能更新到v的最短距离值更小,但是值相同到v的最短路数量就增加了lushu[v]应该累        
                //加lushu[u],一开始写的lushu[v]++,错到身心俱疲    
            }
            if(sign)
            {
                if(vis[v]==0)
                {
                    qwq.push(v);
                    vis[v]=1;
                }
            }
        }
 
    }
}
 
int main()
{
    cnt=0;
    cin>>N>>K>>tou>>wei;
    Q[tou]=1;
    P[1]=tou;
    for(int i=2;i<=N;i++)
    {
        cin>>ch>>army[i];
        Q[ch]=i;
        P[i]=ch;
    }
    while(K--)
    {
        cin>>s1>>s2>>shu;
        G[Q[s1]].push_back(data{Q[s2],shu});
        G[Q[s2]].push_back(data{Q[s1],shu});
    }
    SPFA(1);
 
    //存路径时path[]数组是倒着存路径关系的,比如1->3->7 path数组存的是path[7]=3;path[3]=1
    //下面用while循环把路径存到res[]数组里,倒着输出这一串数字刚好是正向的路径
    int jieshu=Q[wei];
    while(jieshu!=0)
    {
        res[++cnt]=jieshu;
        jieshu=path[jieshu];
    }
    for(int i=cnt;i>=1;i--)
    {
        cout<<P[res[i]];
        if(i==1)cout<<endl;
        else cout<<"->";
    }
    cout<<lushu[Q[wei]]<<" "<<dist[Q[wei]]<<" "<<shadi[Q[wei]]<<endl;
    return 0;
}



Tag:
相关文章

发表评论: