2959. 关闭分部的可行集合数目 Hard

一个公司在全国有 n 个分部,它们之间有的有道路连接。一开始,所有分部通过这些道路两两之间互相可以到达。

公司意识到在分部之间旅行花费了太多时间,所以它们决定关闭一些分部(也可能不关闭任何分部),同时保证剩下的分部之间两两互相可以到达且最远距离不超过 maxDistance 。

两个分部之间的 距离 是通过道路长度之和的 最小值 。

给你整数 n ,maxDistance 和下标从 0 开始的二维整数数组 roads ,其中 roads[i] = [ui, vi, wi] 表示一条从 ui 到 vi 长度为 wi的 无向 道路。

请你返回关闭分部的可行方案数目,满足每个方案里剩余分部之间的最远距离不超过 maxDistance

注意,关闭一个分部后,与之相连的所有道路不可通行。

注意,两个分部之间可能会有多条道路。

示例 1:

输入:n = 3, maxDistance = 5, roads = [[0,1,2],[1,2,10],[0,2,10]]
输出:5
解释:可行的关闭分部方案有:
- 关闭分部集合 [2] ,剩余分部为 [0,1] ,它们之间的距离为 2 。
- 关闭分部集合 [0,1] ,剩余分部为 [2] 。
- 关闭分部集合 [1,2] ,剩余分部为 [0] 。
- 关闭分部集合 [0,2] ,剩余分部为 [1] 。
- 关闭分部集合 [0,1,2] ,关闭后没有剩余分部。
总共有 5 种可行的关闭方案。

示例 2:

输入:n = 3, maxDistance = 5, roads = [[0,1,20],[0,1,10],[1,2,2],[0,2,2]]
输出:7
解释:可行的关闭分部方案有:
- 关闭分部集合 [] ,剩余分部为 [0,1,2] ,它们之间的最远距离为 4 。
- 关闭分部集合 [0] ,剩余分部为 [1,2] ,它们之间的距离为 2 。
- 关闭分部集合 [1] ,剩余分部为 [0,2] ,它们之间的距离为 2 。
- 关闭分部集合 [0,1] ,剩余分部为 [2] 。
- 关闭分部集合 [1,2] ,剩余分部为 [0] 。
- 关闭分部集合 [0,2] ,剩余分部为 [1] 。
- 关闭分部集合 [0,1,2] ,关闭后没有剩余分部。
总共有 7 种可行的关闭方案。

示例 3:

输入:n = 1, maxDistance = 10, roads = []
输出:2
解释:可行的关闭分部方案有:
- 关闭分部集合 [] ,剩余分部为 [0] 。
- 关闭分部集合 [0] ,关闭后没有剩余分部。
总共有 2 种可行的关闭方案。

提示:

 ·1 <= n <= 10

 ·1 <= maxDistance <= 105

 ·0 <= roads.length <= 1000

 ·roads[i].length == 3

 ·0 <= ui, vi <= n - 1

 ·ui != vi

 ·1 <= wi <= 1000

 ·一开始所有分部之间通过道路互相可以到达。

题目大意:计算满足删除部分结点后各结点间的最短路径不大于maxDistance的删除方案的总数。

分析:由题可知最多只有10个结点,因此可以遍历所有的删除方案,用Floyd算法计算每个方案中各结点间的最短路径并判断是否所有最短路径都不大于maxDistance,若符合条件则方案总数+1。

class Solution {
public:
    int numberOfSets(int n, int maxDistance, vector<vector<int>>& roads) {
        int M=1<<n,ans=0,x,y,isValid;
        vector<vector<int>> map(n,vector<int>(n));
        vector<bool> f(n);
        for(int k=0;k<M;++k){
            for(int i=0;i<n;++i){
                f[i]=k&(1<<i);
                for(int j=i;j<n;++j) map[i][j]=map[j][i]=1000000;
            }
            for(const auto& road:roads){
                x=road[0];y=road[1];
                if(f[x]&&f[y]) map[x][y]=map[y][x]=min(map[x][y],road[2]);
            }
            for(int node=0;node<n;++node){
                if(!f[node]) continue;
                for(int i=0;i<n;++i){
                    if(!f[i]) continue;
                    for(int j=i+1;j<n;++j){
                        if(f[j]) map[i][j]=map[j][i]=min(map[i][j],map[i][node]+map[node][j]);
                    }
                }
            }
            isValid=1;
            for(int i=0;i<n&&isValid;++i){
                if(!f[i]) continue;
                for(int j=i+1;j<n&&isValid;++j){
                    if(f[j]&&map[i][j]>maxDistance) isValid=0;
                }
            }
            ans+=isValid;
        }
        return ans;
    }
};
  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值