【CSP】202012-4 食材運輸 70% 一點思路

dudujerry發表於2024-04-12

對於K==M的情況,問題重點是:如何統計從某點出發,遍歷需要某食材的所有酒店最小權重和。

考慮到N規模很小,因此可以直接列舉從每個點出發的權重和,問題就轉化為如何求從某點出發,遍歷某食材的權重和。由於圖為一棵樹,所有該權重和是唯一的。

有兩個限制條件:如何知道某食材的全部酒店已經經過、每個點如何到達下一個點(即遍歷的順序/路徑)。

再仔細思考問題,若從某點出發遍歷樹中的任意子集S並最後回到該點,將該點看作根節點,則其到每個節點所經過的路徑(記作E)都要走兩遍。

如果不回到該點,那麼就可以選一個距離根節點最遠的點減去,因為這條路徑不需要走兩遍。

發現這個關鍵結論後,就可以知道兩個限制條件如何解決:直接將該點作為根節點遍歷整棵樹,用dp儲存在E上的路徑總和,轉移方程為

dp[u] = \sigma_{i屬於sons} (sons子樹存在需求酒店或son本身為需求酒店)*dp[i] + w

這樣就可以不用在意遍歷的順序。啟示是,不能總用線性搜尋的方式看待問題,深入考慮到樹狀問題的子結構性質,可以解決許多看起來毫不相關的問題。

【CSP】202012-4 食材運輸 70% 一點思路
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <string.h>

#define up(l,r,i) for(int i=l;i<=r;i++)
#define dn(l,r,i) for(int i=r;i>=l;i--)

typedef long long ll;

#define int ll

using namespace std;

inline int _max(const int& a,const int& b){return a>b?a:b;}
inline int _min(const int& a,const int& b){return a<b?a:b;}

const int MAXN = 104,MAXM = 15;

struct Node{
    int to,w,nxt;
    Node():to(0),w(0),nxt(0){}
}nd[MAXN<<1];

int head[MAXN],ecnt;
int fa[MAXN],dp[MAXN];

void add(int a,int b,int w){
    nd[++ecnt].to = b;
    nd[ecnt].w = w;
    nd[ecnt].nxt = head[a];
    head[a] = ecnt;
}

int ned[MAXN][MAXM];
int n,m,k;

int dfs(int u,int tp){
    int mx = 0;
    for(int i = head[u]; i; i = nd[i].nxt){
        int v = nd[i].to;
        int w = nd[i].w;
        if(fa[u] == v) continue;
        fa[v] = u;
        
        int t = dfs(v,tp);
        if(ned[v][tp] || dp[v]){
            dp[u] += dp[v] + (w<<1);
            mx = _max(mx,t+w);
        }
    }
    return mx;
}

signed main()
{
    //freopen("y.in","r",stdin);

    ios::sync_with_stdio(false);

    cin>>n>>m>>k;
    up(1,n,i){
        up(1,k,j){
            cin>>ned[i][j];
        }
    } 
    up(1,n-1,i){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }

    //if(n == 6 && m == 1 && k == 2) {cout<<15<<endl;return 0;}
    
    int mx = 0;
    up(1,k,i){
        int mi = 0x777777f;
        up(1,n,j){
            memset(dp,0,sizeof(dp));
            memset(fa,0,sizeof(fa));
            int t = dfs(j,i);
            int ans = dp[j] - t;
            mi = _min(mi,ans);
        }
        //printf("對於型別%lld,計算結果為%lld\n",i,mi);
        mx = _max(mx,mi);
    }

    cout<<mx;

    return 0;
}
70%

相關文章