【CSP】202012-4 食材运输 70% 一点思路

对于K==M的情况,问题重点是:如何统计从某点出发,遍历需要某食材的所有酒店最小权重和。

考虑到N规模很小,因此可以直接枚举从每个点出发的权重和,问题就转化为如何求从某点出发,遍历某食材的权重和。由于图为一棵树,所有该权重和是唯一的。

有两个限制条件:如何知道某食材的全部酒店已经经过、每个点如何到达下一个点(即遍历的顺序/路径)。

再仔细思考问题,若从某点出发遍历树中的任意子集S并最后回到该点,将该点看作根节点,则其到每个节点所经过的路径(记作E)都要走两遍。

如果不回到该点,那么就可以选一个距离根节点最远的点减去,因为这条路径不需要走两遍。

发现这个关键结论后,就可以知道两个限制条件如何解决:直接将该点作为根节点遍历整棵树,用dp存储在E上的路径总和,转移方程为

dp[u] = \sigma_{i属于sons} (sons子树存在需求酒店或son本身为需求酒店)*dp[i] + w

这样就可以不用在意遍历的顺序。启示是,不能总用线性搜索的方式看待问题,深入考虑到树状问题的子结构性质,可以解决许多看起来毫不相关的问题。

#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%

 

posted @ 2024-04-12 20:36  dudujerry  阅读(19)  评论(0编辑  收藏  举报