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

题目描述

原题链接:2959.关闭分部的可行集合数目

解题思路

考虑暴力枚举每一种关闭分部的可能性,也就是枚举每一种分部开着的可能性。我们假设以二进制的1表示分部开着,0表示分部关闭。以一个十位的二进制数来表示这n个分部的开关情况。
由于题目的限制 1 ≤ n ≤ 10 1\leq n \leq 10 1n10,因此最多有 2 10 = 1024 2^{10}=1024 210=1024种情况。而枚举每一种情况又需要进行一次Floyd算法,因此整体的时间复杂度是 o ( 2 n ∗ n 3 ) o(2^n*n^3) o(2nn3)。带入 n = 10 n=10 n=10,最多也就是 1 0 6 10^6 106左右,可以过掉。
总的来说,我们先初始化已知边,由于两个点之间刚开始可能有多条边,因此我们只需要保存距离最小的边。之后我们枚举每一种情况,用一个tool[i]数组来表示第i个分部是否被选中。我们对每一种情况都使用一次Floyd算法,注意这时候我们需要判断一下中间点k是否被选中,如果没有判断则可能会更新所选中分布之间的距离。最后我们需要看看被选中的分部之间的距离是不是都小于maxDistence

C++代码

Floyd算法代码
void floyd(vector<vector<int>>& d)
    {
        for (int k = 0; k < d.size(); k ++ ){
            if(tool[k] == 0) continue;
            for (int i = 0; i < d.size(); i ++ ) {
                for (int j = 0; j < d.size(); j ++ ) {
                    d[i][j] = d[j][i] = min(d[i][j], d[i][k] + d[k][j]);
                }
            }
        }
    }

要注意这里的d[i][j] = d[j][i] = min(d[i][j], d[i][k] + d[k][j]);必须要给两个方向的都赋值,因为本题是一个无向图。如果只给一个方向赋值则会造成答案错误,我之前就在这里卡了好久TAT。

完整AC代码
class Solution {
public:
    int tool[11];
    void floyd(vector<vector<int>>& d)
    {
        for (int k = 0; k < d.size(); k ++ ){
            if(tool[k] == 0) continue;
            for (int i = 0; i < d.size(); i ++ ) {
                for (int j = 0; j < d.size(); j ++ ) {
                    d[i][j] = d[j][i] = min(d[i][j], d[i][k] + d[k][j]);
                }
            }
        }
    }
    int numberOfSets(int n, int maxDistance, vector<vector<int>>& roads) {
        int cnt = 0;
        for(int i = 0; i < 1 << n; i++)
        {
            memset(tool, 0, sizeof(tool));
            for(int j = 0; j < n; j++)
            {
                if(((i >> j) & 1) == 1)
                {
                    tool[j] = 1;
                }
            }
            vector<vector<int>> d;
            d.resize(n, vector<int>(n, 1010));
            for(int j = 0; j < n; j++) d[j][j] = 0;
            for(int j = 0; j < roads.size(); j++)
            {
                int x = roads[j][0];
                int y = roads[j][1];
                int dis = roads[j][2];
                d[x][y] = d[y][x] = min(d[x][y], dis);
            }
            floyd(d);
            bool flag = true;
            for(int j = 0; j < n; j++)
            {
                for(int k = j; k < n; k++)
                {
                    if(tool[j] == 1 && tool[k] == 1)
                    {
                        if(maxDistance < d[j][k]) {
                            flag = false;
                            break;
                        }
                    }
                }
                if(!flag) {
                    break;
                }
            }
            if(flag) {
                cnt++;
            }
        }
        return cnt;
    }
};
  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值