2023年杭电多校第一场----B (2). City Upgrading

样例:

输入

2
7
13 20 1 20 6 9 8
1 2
1 3
2 4
2 5
3 6
5 7
4
1 17 13 4
1 2
1 3
3 4

输出

27
5

 题意简述:

在一个图上, 一个路由器可以覆盖当前这个节点以及和他相邻的节点, 每个节点部署都有相应的花费, 问你用路由器把这个图全部覆盖掉的最小花费。

思路分析:

很显然这是一道树形DP的题。对于这种题一般要分析一下状态转移方程怎么来的。

使用Y氏动态规划分析法

状态表示:

        集合:f[i][0]表示以i为根节点,当前这个节点被父节点看着的情况

                f[i][1]表示以i为根节点,当前这个节点被子节点看着的情况

                f[i][2]表示以i为根节点,当前这个节点被自己看着的情况

        属性:最小值

状态计算:

        三种情况:

         情况一:假设这个节点被父节点看着,那么这个节点是可以不放的,所以他的子节点就只有两种情况,被子节点看着或者自己看着自己,两者取最小值。

        这种的状态方程为:f[i][0] += min(f[j][1], f[j][2])

        注:i为当前的节点, j为子节点

        情况二:假设这个节点被子节点看着,那么这个节点的子节点是必须要放的,那么只要让他的子节点的其中一个子节点放就行了.

所以 状态转移的方程为:f[i][1] = min( f[j][2] + sum(min( f [k][1],f[k][2] ) ) ))

           注:i是当前的节点, j是i的子节点, k是  i的除了j的子节点的, 因为j一定放,所以其他的子节点一定不放(因为子节点只放一个),所以其他子节点有两种状态,一种是被他的父节点看着(这个子节点可能有其他的父节点) ,也可以被自己看着(反正就是不放)。这样就会发现和情况一有点类似。

        情况三, 这个节点被自己看着。也就是他的子节点父节点都是可有可不有的,所以让那三种情况取最小值就行了。

        即状态转移方程为:f[i][2] += min(f[j][2],f[j][0], f[j][1]);

       注:i是当前的节点,j是子节点

特殊处理:情况二方程进一步化简,

算完一轮的f[i][0]表示所有子节点要么让自己的父节点看着,要么自己看着自己的所有情况

即f[i][0] = sum(min(f[j][1], f[j][2]));i为当前的节点, j为子节点

所以只让其中一个子节点j放的情况,即除了j节点放,其他的节点可放,或者让他自己的子节点看着的情况由   f[j][2] + sum(min( f [k][1],f[k][2] )  其中sum(min( f [k][1],f[k][2] )意思为其他子节点无父亲节点了,他这里可以被子节点看着的情况,也就是可以转化为

所有的情况一中扣去假设j有父亲节点,这个节点可以自己看着自己或者让他的子节点看着的情况, 所以公式转换为  sum(min( f [k][1],f[k][2] )= f[i][0] - min(f[j][1], f[j][2]).

所以最终的式子化为  f[i][1] = min( f[j][2] + f[i][0] - min(f[j][1], f[j][2])这样就优化了一层循环。

具体代码和注释如下

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 2e3 + 10;
int f[N][3], w[N];
vector<int> vc[N];
int isroot[N];

void dfs(int u, int fa)          //f[u][0]  父节点看着u                  
{                                //f[u][1] 子节点看着u 
    f[u][0] = 0;f[u][2] = w[u];  //f[u][2]  自己看着自己u
    f[u][1] = 1e9;
    for(auto v : vc[u])
    {
        if(fa == v) continue;
        dfs(v, u);
        f[u][0] += min(f[v][2], f[v][1]);//v没有父节点看着
        f[u][2] += min(f[v][2], min(f[v][0], f[v][1]));//所有情况都有
    }
    for(auto v : vc[u])//v节点上放 //w[v] + sum(min(f[k][1], f[k][2])), k表示除v以外的节点
    {
        f[u][1] = min(f[u][1], f[v][2] + f[u][0] - min(f[v][1], f[v][2]) );//这个节点放, 并且其他节点没有父节点看着的状态总数
    }
}
void solve()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i ++) vc[i].clear();
    for(int i = 1; i <= n; i ++) cin >> w[i];
    for(int i = 1; i < n; i ++)
    {
        int u, v;
        cin >> u >> v;
        vc[u].push_back(v);
        isroot[v] = 1;
    }
    int root = 1;
    while(isroot[root]) root ++;
    dfs(root, -1);
    if(n == 1)
    {
        cout << w[root];
    }
    else 
    {
        cout << min(f[root][2], f[root][1]);//因为这个节点没有父节点,所以没有不用考虑父节点放的情况
    }
    cout << "\n";
    
}

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这个错误提示是因为你当前使用的pip版本较旧,建议通过执行命令'python -m pip install --upgrade pip'来升级pip。\[1\]然而,根据你提供的引用内容,你尝试了几种解决方案但都没有成功。其中一种解决方案是在升级pip时指定镜像源,比如使用豆瓣镜像源。你可以尝试执行以下命令来升级pip并指定豆瓣镜像源:'python -m pip install --upgrade pip -i https://pypi.doubanio.com/simple/ --trusted-host pypi.doubanio.com'。\[3\]另外,还有一种解决方案是以管理员身份运行命令提示符,这可能会解决一些权限问题。\[3\]希望这些解决方案能够帮助你解决问题。 #### 引用[.reference_title] - *1* *3* [使用pip安装第三方库报错 You should consider upgrading via the ‘python -m pip install --upgrade pip...](https://blog.csdn.net/m0_53129012/article/details/110430873)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [pip 更新报错——You should consider upgrading via the ‘python.exe -m pip install --upgrade pip‘ ...](https://blog.csdn.net/weixin_45980783/article/details/123045744)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值