2020年團體程式設計天梯賽-總決賽 L2-4 網紅點打卡攻略

zdragon的小迷弟發表於2020-11-29

題目:
一個旅遊景點,如果被帶火了的話,就被稱為“網紅點”。大家來網紅點遊玩,俗稱“打卡”。在各個網紅點打卡的快(省)樂(錢)方法稱為“攻略”。你的任務就是從一大堆攻略中,找出那個能在每個網紅點打卡僅一次、並且路上花費最少的攻略。

輸入格式:
首先第一行給出兩個正整數:網紅點的個數 N(1<N≤200)和網紅點之間通路的條數 M。隨後 M 行,每行給出有通路的兩個網紅點、以及這條路上的旅行花費(為正整數),格式為“網紅點1 網紅點2 費用”,其中網紅點從 1 到 N 編號;同時也給出你家到某些網紅點的花費,格式相同,其中你家的編號固定為 0。
再下一行給出一個正整數 K,是待檢驗的攻略的數量。隨後 K 行,每行給出一條待檢攻略,格式為:n V​1​​ V​2​​ ⋯ V​n
其中 n(≤200) 是攻略中的網紅點數,Vi是路徑上的網紅點編號。這裡假設你從家裡出發,從V1開始打卡,最後從 Vn回家。

輸出格式:

在第一行輸出滿足要求的攻略的個數。
在第二行中,首先輸出那個能在每個網紅點打卡僅一次、並且路上花費最少的攻略的序號(從 1 開始),然後輸出這個攻略的總路費,其間以一個空格分隔。如果這樣的攻略不唯一,則輸出序號最小的那個。
題目保證至少存在一個有效攻略,並且總路費不超過 1e9.

輸入樣例:

6 13
0 5 2
6 2 2
6 0 1
3 4 2
1 5 2
2 5 1
3 1 1
4 1 2
1 6 1
6 3 2
1 2 1
4 5 3
2 0 2
7
6 5 1 4 3 6 2
6 5 2 1 6 3 4
8 6 2 1 6 3 4 5 2
3 2 1 5
6 6 1 3 4 5 2
7 6 2 1 3 4 5 2
6 5 2 1 4 3 6

輸出樣例:

3
5 11

樣例說明:
第 2、3、4、6 條都不滿足攻略的基本要求,即不能做到從家裡出發,在每個網紅點打卡僅一次,且能回到家裡。所以滿足條件的攻略有 3 條。
第 1 條攻略的總路費是:(0->5) 2 + (5->1) 2 + (1->4) 2 + (4->3) 2 + (3->6) 2 + (6->2) 2 + (2->0) 2 = 14;
第 5 條攻略的總路費同理可算得:1 + 1 + 1 + 2 + 3 + 1 + 2 = 11,是一條更省錢的攻略;
第 7 條攻略的總路費同理可算得:2 + 1 + 1 + 2 + 2 + 2 + 1 = 11,與第 5 條花費相同,但序號較大,所以不輸出。

打比賽的時候,疑惑為什麼樣例說明第3條不滿足。卡在了閱讀理解上了。

題解:給你k個攻略,每個攻略要求你檢查可行性。如果可行(題目保證一定有可行的),再求攻略的最少花費,如果有相同的最少花費攻略,優先輸出序號最小的。第一行輸出可行的攻略數量,第二行輸出最少花費的最小ID和最少花費。
建議用鄰接矩陣建圖。


可行性:
1、n個點都要訪問且只訪問一次(用一個vis陣列記錄一下輸入的攻略路線:vis[v[i]]++,檢查一下vis[1~n],要求都是1)。2、要求從0出發經過攻略路線再到0要有邊連線(在檢查的過程中計算花費)。
最少花費ID和最少花費:在可行性的基礎上選擇一下就好。

 

補題程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 200+5;
#define inf 0x3f3f3f3f
#define mod 998244353
#define pre(a,b,c) for(int a=b;a<c;a++)
#define pres(a,b,c) for(int a=b;a<=c;a++)
int G[N][N];
int a[N],sum,q,vis[N],n,m;
bool BFS(int s) {
    for(int j = 1;j <= n;j++) {
        if(vis[j]!=1) {
            return false;
        }
    }
    sum = 0;
    for(int i = 0;i < q;i++) {
        if(G[s][a[i]]==inf) {
            return false;
        }
        sum += G[s][a[i]];
        s = a[i];
    }
    if(G[s][0]==inf) {
        return false;
    }
    sum += G[s][0];
    return true;
}
int main() {
    cin>>n>>m;
    memset(G,inf,sizeof G);
    for(int i = 0,u,v,w;i < m;i++) {
        cin>>u>>v>>w;
        G[u][v] = G[v][u] = w;
    }
    int mi = inf,k,id,cnt = 0;
    cin>>k;
    for(int i = 0;i < k;i++) {
        cin>>q;
        memset(vis,0,sizeof vis);
        for(int j = 0;j < q;j++) {
            cin>>a[j];
            vis[a[j]]++;
        }
        if(BFS(0)) {
            if(mi > sum) {
                id = i+1;
                mi = sum;
            }
            cnt++;
        }
    }
    cout<<cnt<<endl;
    cout<<id<<' '<<mi<<endl;
}

 

相關文章