C4top-直搗黃龍(dijkstra-最短路數目+多重條件判斷)

kewlgrl發表於2017-03-23
直搗黃龍  

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

輸入格式:

輸入第一行給出2個正整數N(2 \le N \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
 
  • 時間限制:150ms
  • 記憶體限制:64MB
  • 程式碼長度限制:16kB
  • 判題程式:系統預設
  • 作者:陳越
  • 單位:浙江大學

題目判定

解題思路
被這道題噁心了大半天…一開始用的Bellman Ford最後發現不能統計最短路數目,百度了一下似乎只有dijkstra和SPFA可以。
我這道題把起始點標記為1,剩下的從2~n標記。用map來做城市名和編號之間的轉換。
條件真是太多啦,真是蠻鍛鍊我的…不過過了真的好開心ヾ(o◕∀◕)ノヾ

解題程式
#include<bits/stdc++.h>
using namespace std;
#define INF 0xfffffff
#define MAXN 1010
string st,en;
map<string,int> mano;//城市名對應的編號
map<int,string> noma;//編號對應的城市名

struct Node
{
    int dist;//最短路長度
    int town;//城鎮數
    int cnt;//殺敵數
} a[MAXN];//對於每個城鎮
int n,m;//頂點數和邊數
bool used[MAXN];//是否使用過
int dis[MAXN];//最短路的數量
int pre[MAXN];//pre[i]表示v0到vi的最短路徑上vi的前一個頂點的序號
int num[MAXN];//殺敵數
int cost[MAXN][MAXN];//邊權

void dijkstra(int s)//s到其它點的最短路
{
    for(int i=0; i<=n; ++i)//初始化
    {
        a[i].dist=INF;
        a[i].town=a[i].cnt=0;
        dis[i]=0;
        used[i]=false;
        pre[i]=-1;
    }
    a[s].dist=0;//起始點的最短路是0
    a[s].town=1;//起始點的城鎮數是1
    dis[s]=1;//起始點的最短路數是1
    while(true)
    {
        int v=-1,minx=INF;
        for(int u=1; u<=n; u++)//從未使用過的頂點中選擇一個距離最小的頂點
            if(!used[u]&&minx>a[u].dist)
            {
                minx=a[u].dist;
                v=u;
            }
        if(v==-1) break;
        used[v]=true;
        for(int u=1; u<=n; ++u)
        {
            if(used[u]) continue;
            if(a[v].dist+cost[v][u]<a[u].dist)//路徑更多
            {
                a[u].dist=a[v].dist+cost[v][u];//更新最短路
                a[u].town=a[v].town+1;//加入當前城鎮更新城鎮數
                a[u].cnt=a[v].cnt+num[u];//加入在當前城鎮的殺敵數更新
                pre[u]=v;//記錄路徑
                dis[u]=dis[v];//最短路數量
            }
            else if(cost[v][u]!=INF&&cost[v][u]+a[v].dist==a[u].dist)
            {
                dis[u]+=dis[v];//更新最短路數量
                if(a[u].town<a[v].town+1)//城鎮更多
                {
                    a[u].dist=cost[v][u]+a[v].dist;
                    a[u].town=a[v].town+1;
                    a[u].cnt=a[v].cnt+num[u];
                    pre[u]=v;
                }
                else if(a[u].cnt<a[v].cnt+num[u])//殺敵數更多
                {
                    a[u].dist=cost[v][u]+a[v].dist;
                    a[u].town=a[v].town+1;
                    a[u].cnt=a[v].cnt+num[u];
                    pre[u]=v;
                }
            }
        }
    }
}

vector<int> get_path(int t)//輸出路徑,計算到頂點n的最短路
{
    vector<int> path;
    for(; t!=-1; t=pre[t])
        path.push_back(t);
    reverse(path.begin(),path.end());
    return path;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("G:/cbx/read.txt","r",stdin);
//freopen("G:/cbx/out.txt","w",stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    int i;
    cin>>n>>m;
    cin>>st>>en;//起終點城鎮名
    mano[st]=1;
    noma[1]=st;
    num[1]=0;//起點敵人數為0
    for(i=2; i<=n; ++i)
    {
        string str;
        int t;
        cin>>str>>t;
        mano[str]=i;//記錄城市名對應編號
        noma[i]=str;//記錄編號對應城市名
        num[i]=t;//記錄敵人數量
    }
    for(int i=0; i<=n; ++i)//初始化
        for(int j=0; j<=n; ++j)
            cost[i][j]=INF;
    for(i=0; i<m; i++)
    {
        string s,ss;
        int t;
        cin>>s>>ss>>t;
        cost[mano[s]][mano[ss]]=t;//無向圖
        cost[mano[ss]][mano[s]]=t;
    }
    /*map<string,int>::iterator it;
    for(it=mano.begin(); it!=mano.end(); it++)
        cout<<it->first<<" "<<it->second<<endl;
        cout<<mano[st]<<endl;*/
    int s=mano[st];//起始點
    dijkstra(s);
    //路徑還原,輸出路徑
    vector<int> path;
    path=get_path(mano[en]);//輸出路徑
    int len=path.size();
    for(int i=0; i<len-1; ++i)
        cout<<noma[path[i]]<<"->";
    cout<<noma[path[len-1]]<<endl;
    cout<<dis[mano[en]]<<" "<<a[mano[en]].dist<<" "<<a[mano[en]].cnt<<endl;//輸出最快進攻路徑的條數、最短進攻距離、殲敵總數
    return 0;
}
/*
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
*/



相關文章