SRM622 Ethernet

思路:
不难看出计算maxdist,就是一个子树中一个点到其它点的最大距离和次大距离之和。
那么就可以在每个点上求出到其它点的距离,这里求距离用到dp,
然后贪心地,只需要考虑每个点的最大距离和次大距离,就可以求出每个点的答案。
当然也以直接暴力 DP D P ,定义 dp[x][d] d p [ x ] [ d ] 为subtree(x)中最大到根距离为x的块数。
然后直接暴力转移即可。

code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;i++)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define db double
#define LL long long 
#define INF 0x3f3f3f3f                         
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
inline LL Max(LL &x,LL y){return x>y?x:y;}
inline LL Min(LL &x,LL y){return x<y?x:y;}

#define N 52
#define M 502

int n;
struct edge{
    int to,cost;
};
vector<edge>E[N];

int dp[M];

class Ethernet {
public:

    int Mx;

    int dfs(int x){
        vector<int>dis;
        dis.pb(0);
        int res=0;
        int &t=dp[x];
        SREP(i,0,E[x].size()){
            int y=E[x][i].to;
            res+=dfs(y);
            dis.pb(dp[y]+E[x][i].cost);
        }
        sort(dis.begin(),dis.end());//排序距离
        while(dis.size()>1 && dis[dis.size()-1]+dis[dis.size()-2]>Mx){// judge and merge
            res++;
            dis.pop_back();
        }
        t=dis[dis.size()-1];
        return res;
    }

    int connect(vector <int> parent, vector <int> dist, int maxDist) {
        n=parent.size();
        Mx=maxDist;
        SREP(i,0,n)E[parent[i]].pb((edge){i+1,dist[i]});
        return dfs(0)+1; 
    }
};

code(纯DP):

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <cassert>
#include <iostream>
#include <sstream>
using namespace std;
#define rep(i,a,n) for(int i=a,_n=n;i<_n;++i)
#define repp(i,a,n) for(int i=a,_n=n;i<=_n;++i)
#define per(i,a,n) for(int i=n-1,_a=a;i>=_a;--i)
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define sz(x) ((int)(x).size())
#define accu accumulate
#define two(x) (1<<(x))
#define twol(x) (1ll<<(x))
#define clr(a) memset(a,0,sizeof(a))
#define debug(x) cout<<#x<<" = "<<x<<endl;
typedef vector<int> vi;
typedef vector<string> vs;
typedef long long ll;
typedef double db;
typedef long double ldb;
typedef pair<int,int>pii;
typedef vector<pii> vpii;
const int INF=0x3f3f3f3f;


int n;
struct node{
    int v,w;
};
vector<node>E[55];
int dp[55][555],tmp[555];
void Min(int &x,int y){
    if(y<x) x=y;    
}
class Ethernet {
public:
    void DP(int x,int f,int maxDist){
        int ok=0;
        for(int i=0;i<E[x].size();i++){
            int V=E[x][i].v,W=E[x][i].w;
            if(V==f) continue;
            DP(V,x,maxDist);
            for(int j=0;j<=maxDist;j++) tmp[j]=INF;
            if(!ok){
                for(int j=0;j<=maxDist;j++) Min(tmp[0],dp[V][j]+1);
                for(int j=0;j+W<=maxDist;j++) Min(tmp[j+W],dp[V][j]);
            }
            else{
                for(int t=0;t<=maxDist;t++) for(int j=0;j<=maxDist;j++) Min(tmp[t],dp[x][t]+dp[V][j]+1);
                for(int j=0;j+W<=maxDist;j++){
                    for(int t=0;t<=maxDist;t++){
                        if(j+W+t<=maxDist) Min(tmp[max(t,j+W)],dp[x][t]+dp[V][j]);
                    }
                }
            }
            for(int j=0;j<=maxDist;j++) dp[x][j]=tmp[j];
            ok=1;
        }
        if(!ok){
            dp[x][0]=0;
        }
    }
    int connect(vector <int> parent, vector <int> dist, int maxDist) {
        n=parent.size()+1;
        memset(dp,63,sizeof(dp));
        for(int i=0;i<=n;i++) E[i].clear(); 
        for(int i=0;i<n-1;i++){
            E[parent[i]].pb((node){i+1,dist[i]});
            E[i+1].pb((node){parent[i],dist[i]});   
        }
        DP(0,-1,maxDist);
        int ans=INF;
        for(int i=0;i<=maxDist;i++) Min(ans,dp[0][i]);
        return ans+1;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值