洛谷P1111 修复公路P8783统计子矩阵

P1111 修复公路

https://www.luogu.com.cn/problem/P1111

 题目背景

A 地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些公路。

题目描述

给出 A 地区的村庄数 N,和公路数 M,公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)。

输入格式

第 1 行两个正整数 N,M。

下面 M行,每行 3 个正整数 x,y,t,告诉你这条公路连着 x,y 两个村庄,在时间t时能修复完成这条公路。

 输出格式

如果全部公路修复完毕仍然存在两个村庄无法通车,则输出 -1,否则输出最早什么时候任意两个村庄能够通车。

class DSU:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        rootX = self.find(x)
        rootY = self.find(y)
        if rootX != rootY:
            if self.rank[rootX] > self.rank[rootY]:
                self.parent[rootY] = rootX
            elif self.rank[rootX] < self.rank[rootY]:
                self.parent[rootX] = rootY
            else:
                self.parent[rootY] = rootX
                self.rank[rootX] += 1
            return True
        return False

def earliestAllConnected(N, M, roads):
    dsu = DSU(N)
    roads.sort(key=lambda x: x[2])  # 按修复时间排序
    latestTime = 0
    connectedComponents = N

    for x, y, t in roads:
        if dsu.union(x - 1, y - 1):
            latestTime = max(latestTime, t)
            connectedComponents -= 1
            if connectedComponents == 1:  # 所有村庄都连接起来了
                return latestTime

    if connectedComponents > 1:
        return -1  # 仍然存在无法通车的村庄
    return latestTime

# 从标准输入读取数据
N, M = map(int, input().split())
roads = [tuple(map(int, input().split())) for _ in range(M)]

# 输出结果
print(earliestAllConnected(N, M, roads))

P8783 统计子矩阵

 题目描述

给定一个 N M 的矩阵 A,请你统计有多少个子矩阵 (最小 1*1 , 最大 N* M) 满足子矩阵中所有数的和不超过给定的整数 K。

 输入格式

第一行包含三个整数 N, M 和 K。

之后 N 行每包含 M 个整数, 代表矩阵 A。

 输出格式

一个整数代表答案。

int main() {
    int n, m, k;
    long long ans = 0; // 用于存储最终的答案
    scanf_s("%d%d%d", &n, &m, &k); // 输入n, m, k

    // 输入矩阵并计算前缀和
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            scanf_s("%d", &a[i][j]);
            // 计算前缀和
            s[i][j] = a[i][j] + s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1];
        }
    }

    // 枚举所有可能的子矩阵,并统计满足条件的子矩阵数量
    for (int i = 1; i <= n; ++i) {
        for (int j = i; j <= n; ++j) {
            for (int l = 1, r = 1; r <= m; ++r) {
                // 调整左边界l,使得子矩阵的和不超过k
                while (l <= r && s[j][r] - s[j][l - 1] - s[i - 1][r] + s[i - 1][l - 1] > k) {
                    ++l;
                }
                // 统计数量
                ans += (r - l + 1);
            }
        }
    }

    // 输出结果
    printf("%lld\n", ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值