PTA天梯決賽14題直搗黃龍

題目:
5-14 直搗黃龍   (30分)

本題是一部戰爭大片 —— 你需要從己方大本營出發,一路攻城略地殺到敵方大本營。首先時間就是生命,所以你必須選擇合適的路徑,以最快的速度佔領敵方大本營。當這樣的路徑不唯一時,要求選擇可以沿途解放最多城鎮的路徑。若這樣的路徑也不唯一,則選擇可以有效殺傷最多敵軍的路徑。

輸入格式:

輸入第一行給出2個正整數N(2 ≤\leN ≤\le 200,城鎮總數)和K(城鎮間道路條數),以及己方大本營和敵方大本營的代號。隨後N-1行,每行給出除了己方大本營外的一個城鎮的代號和駐守的敵軍數量,其間以空格分隔。再後面有K行,每行按格式城鎮1 城鎮2 距離給出兩個城鎮之間道路的長度。這裏設每個城鎮(包括雙方大本營)的代號是由3個大寫英文字母組成的字符串。

輸出格式:

按照題目要求找到最合適的進攻路徑(題目保證速度最快、解放最多、殺傷最強的路徑是唯一的),並在第一行按照格式己方大本營->城鎮1->...->敵方大本營輸出。第二行順序輸出最快進攻路徑的條數、最短進攻距離、殲敵總數,其間以1個空格分隔,行首尾不得有多餘空格。

輸入樣例:

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

輸出樣例:

PAT->PTA->PDS->DBY
3 30 210

簡要分析:這個題目個人感覺就是枚舉各種路線的走法,然後把滿足條件的路線和最優路線給記錄下來,說起來好像很簡單(笑哭)確實對大牛來說也是很簡單的,可是作爲一隻萌新,我可花了不少時間吶,唉,好了不閒聊了,講正事。

思路:由於要考慮每一條路線,即把每一條路線都給走一遍,所以我們需要回溯(我只能想到這種辦法TAT)還有圖。主要思路理清了這題也不是特別難,總共就兩個思想嘛(寫了那麼久還好意思說),接下來呈上代碼,有可以優化的建議的話請大佬們提出呦。

代碼:

#include<stdio.h>
#include<stdlib.h>
struct cityi            //城市數據
{
    int arrive_;        //可以進入的城市的數目
    struct a                
    {
       int cityid;            //可以進入的城市
       int distance;        //去這個城市所需要的距離
    }arrive[199+20];    //由於城市上限不超過200個,所以我們就算所有城市都能去也只有199條路。
    int enemy;
}citys[199+20];            //同上,不超過200個城市。
int symbol[201]={0};    //標記,如果走過的城市在同一條路線裏不會走第二次,因爲我們要最快速度最短距離。
int rails=0;            //最短距離的路的條數。
int railway[201];        //記錄路線
int truerailway[201];    //最終最優路線
int railway_=0;            //當前經過的城市的個數
int truerailways=-1;    //最優路線經過城市的個數
char cityname[201][4];    //代號轉換,將名字轉換成數字,後面的conversion函數就是轉換功能。
int maxkill=-1;            //最優路線殲敵數
int mixdistance=500000;    //最短進攻距離
int maxtown=-1;            //最優路線解放的城鎮的數目
int conversion(char name[4],int N);        //城鎮代號與數字之間的轉化
int compare(char name1[4],char name2[4]);  //比較城鎮是否相同
void seek(int  now ,int distance,int kill,int town);
int main()            
{
     int N,K;
     char wgzf;
     int amount;
     scanf("%d%d",&N,&K);
     scanf("%c",&wgzf);
     scanf("%s",cityname[0]);
     scanf("%s",cityname[1]);
     citys[0].arrive_=0;                //初始化第一個城鎮(即我方大本營)
     citys[0].enemy=0;                    //我方大本營沒有敵軍
     amount=N-1;                        //題目要求N-1條路線
     int cityname_=2;                    //已經初始化了兩個城鎮,所以從第三個城鎮開始計數
     while(amount--)                        //輸入,並初始化所有城鎮注意由於先前只輸入一個敵方大本營,並沒有輸入敵人人數。
     {
         int number;
        scanf("%s",cityname[cityname_]);
        scanf("%d",&number);
        if(compare(cityname[1],cityname[cityname_]))    //判斷是否爲敵方大本營,是的話初始化敵人個數
        {
            citys[1].enemy=number;
            citys[1].arrive_=0;
        }
        else
        {
            citys[cityname_].enemy=number;
            citys[cityname_].arrive_=0;
            cityname_++;
        }
     }
     while(K--)                                //輸入路線以及距離(注意兩個城鎮都要初始化)
     {
         char name1[4];                        
         char name2[4];
         int distance;
         scanf("%s",name1);
         scanf("%s",name2);
         scanf("%d",&distance);
         int id1,id2;
         id1=conversion(name1,N);
         id2=conversion(name2,N);
         citys[id1].arrive[citys[id1].arrive_].cityid=id2;
         citys[id1].arrive[citys[id1].arrive_++].distance=distance;
         citys[id2].arrive[citys[id2].arrive_].cityid=id1;
         citys[id2].arrive[citys[id2].arrive_++].distance=distance;
    
     }
    
     int times;            //標記大本營
     symbol[0]=1;
     seek(0,0,0,0);
    int hh;
    printf("%s",cityname[0]);
    for(hh=0;hh<truerailways;hh++)
        printf("->%s",cityname[truerailway[hh]]);
    printf("\n");
    printf("%d %d %d",rails,mixdistance,maxkill);
}
int compare(char name1[4],char name2[4])        //比較函數
{
    char *p1,*p2;
    p1=name1;
    p2=name2;
    while(*p1==*p2 && *p1!='\0')
    {
        p1++;
        p2++;
    }
     if(*p1=='\0')
         return 1;
     else
         return 0;
}
int conversion(char name[4],int N)            //轉換函數,轉換城鎮代號
{
     int i;
     for(i=0;i<N;i++)
         if(compare(cityname[i],name))
            return i;
     return -1;
}
void seek(int now ,int distance,int kill,int town)        //查詢函數,枚舉回溯每一條路線
{
    kill+=citys[now].enemy;
    if(now==1)                                            //終止條件,由於先前定義地方大本營位置爲1
    {
        if(distance<=mixdistance)                        //是最短距離的時候進行考慮否則直接跳過
        {
            if(distance<mixdistance)
            {
                rails=0;                                //若是新的最短距離,更新最優路線數量
                mixdistance=distance;
                maxtown=town;
                maxkill=kill;
                truerailways=railway_;
                int times;
                for(times=0;times<railway_;times++)            //記錄最優路線
                    truerailway[times]=railway[times];
            }
            else
                if(town>=maxtown)
                {
                    if(town>maxtown)
                    {
                        maxtown=town;
                        maxkill=kill;
                        truerailways=railway_;
                        int times;
                        for(times=0;times<railway_;times++)        //記錄最優路線
                            truerailway[times]=railway[times];
                    }
                    else
                    if(kill>maxkill)
                    {
                        maxkill=kill;
                        truerailways=railway_;
                        int times;
                        for(times=0;times<railway_;times++)        //記錄最優路線
                            truerailway[times]=railway[times];
                    }
                }
                rails++;
        }
        return ;
    }
    int i;
    for(i=0;i<citys[now].arrive_;i++)                //回溯
    {
        if(symbol[citys[now].arrive[i].cityid]==0)        //判斷是否已被標記
        {
            railway[railway_++]=citys[now].arrive[i].cityid;    //記錄當前路線
            symbol[citys[now].arrive[i].cityid]=1;
            seek(citys[now].arrive[i].cityid,distance+citys[now].arrive[i].distance,kill,town+1);
            symbol[citys[now].arrive[i].cityid]=0;            //
            railway_--;                                        //返回初始狀態
        }
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章