P1796 汤姆斯的天堂梦+P1806 跑步+P8742 [蓝桥杯 2021 省 AB] 砝码称重+P1959 遗址+P8794 [蓝桥杯 2022 国 A] 环境治理

P1796 汤姆斯的天堂梦

题目描述

汤姆斯生活在一个等级为 00 的星球上。那里的环境极其恶劣,每天 1212 小时的工作和成堆的垃圾让人忍无可忍。他向往着等级为 NN 的星球上天堂般的生活。

有一些航班将人从低等级的星球送上高一级的星球,有时需要向驾驶员支付一定金额的费用,有时却又可以得到一定的金钱。

汤姆斯预先知道了从 00 等级星球去 NN 等级星球所有的航线和需要支付(或者可以得到)的金钱,他想寻找一条价格最低(甚至获得金钱最多)的航线。

输入格式

第一行一个正整数 NN(N \le 100N≤100),接下来的数据可分为 NN 个段落,每段的第一行一个整数 K_iKi(K_i \le 100Ki≤100),表示等级为 ii 的星球有 K_iKi 个。

接下来的 K_iKi 行中第 jj 行依次表示与等级为 ii,编号为 jj 的星球相连的等级为 i - 1i−1 的星球的编号和此航线需要的费用(正数表示支出,负数表示收益,费用的绝对值不超过 10001000)。

每行以 00 结束,每行的航线数 \le 100≤100。

输出格式

输出所需(或所得)费用。正数表示支出,负数表示收益。

输入输出样例

输入 #1复制

3

2

1 15 0

1 5 0

3

1 -5 2 10 0

1 3 0

2 40 0

2

1 1 2 5 3 -5 0

2 -19 3 -20 0

输出 #1复制

-1

说明/提示

对于 100 \%100% 的数据,1 \le N \le 1001≤N≤100,1 \le K_i \le 1001≤Ki≤100。

样例解释:

P1796 汤姆斯的天堂梦+P1806 跑步+P8742 [蓝桥杯 2021 省 AB] 砝码称重+P1959 遗址+P8794 [蓝桥杯 2022 国 A] 环境治理_第1张图片
这道题没看图直接看题目看了好久才弄明白数据的含义(太菜,人麻了),先翻译一下输入数据含义
数据分为3个段落
等级为1的星球有2个
与等级为1,编号为1的星球相连的等级为0的星球的编号和航班需要的费用分别为1,15
与等级为1,编号为2的星球相连的等级为0的星球的编号和航班需要的费用分别为1,5
等级为2的星球有3个
与等级为2,编号为1的星球相连的等级为1的星球的编号和航班需要的费用分别为1,-5
与等级为2,编号为1的星球相连的等级为1的星球的编号和航班需要的费用分别为2,10
与等级为2,编号为2的星球相连的等级为1的星球的编号和航班需要的费用分别为1,3
与等级为2,编号为3的星球相连的等级为1的星球的编号和航班需要的费用分别为2,40
等级为3的星球有2个
与等级为3,编号为1的星球相连的等级为2的星球的编号和航班需要的费用分别为1,1
与等级为3,编号为1的星球相连的等级为2的星球的编号和航班需要的费用分别为2,5
与等级为3,编号为1的星球相连的等级为2的星球的编号和航班需要的费用分别为3,5
与等级为3,编号为2的星球相连的等级为2的星球的编号和航班需要的费用分别为2,-19
与等级为3,编号为2的星球相连的等级为2的星球的编号和航班需要的费用分别为3,-20
看到提示的图可以用动态规划来求解,找到状态转移方程:f[i][j] = min(f[i][j], f[i - 1][num] + w)
i表示等级,j是编号,取第i-1级编号为num的星球到第i级编号为j的星球费用的最小值,f[i][j]表示i-1级星球到i级编号为j的星球的费用
#include
using namespace std;
int f[103][103],ans,n,INF=0x3f3f3f3f;
int main()
{
    cin >> n;
    int k,num,w;
    for (int i = 1; i <= n; i++) {//等级
         cin >> k;
         for (int j = 1; j <= k; j++)//编号
         {
             f[i][j] = INF;
             cin >> num;
             while (num != 0)//结束条件
             {
                 cin >> w;
                 f[i][j] = min(f[i][j], f[i - 1][num] + w);
                 cin >> num;
             }
        }
    }
    ans = INF;
    for (int i = 1; i <= k; i++)//k此时的值是最后一级星球个数
        ans = min(ans, f[n][i]);//取倒数第二级星球到最后一级星球费用的最小值
    cout << ans;
    return 0;
}

P1806 跑步

题目描述

路人甲准备跑 nn 圈来锻炼自己的身体,他准备分多次(\gt1>1)跑完,每次都跑正整数圈,然后休息下再继续跑。

为了有效地提高自己的体能,他决定每次跑的圈数都必须比上次跑的多。

可以假设他刚开始跑了 00 圈,那么请问他可以有多少种跑完这 nn 圈的方案?

输入格式

一行一个整数,代表 nn

输出格式

一个整数表示跑完这 nn 圈的方案数。

输入输出样例

输入 #1复制

212

输出 #1复制

995645335

说明/提示

数据规模与约定

对于 100\%100% 的数据,保证 5\le n\le 5005≤n≤500。

状态转移方程f[i][j](跑了i圈最后一次跑j圈) += f[i - j][k](当跑了i圈且这次跑j圈,上一次肯定跑k圈,k

题解 P1806 【跑步】 - 草1药人 的博客 - 洛谷博客 (luogu.com.cn)

#include
using namespace std;
long long n, f[505][505],ans;
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)f[i][i] = 1;
    for (int i = 1; i <= n; i++)//跑的总圈数
        for (int j = 1; j < i; j++)//最后一次跑的圈数
            for (int k = 1; k < j&& j + k <= i; k++)//倒数第二次跑的圈数
                f[i][j] += f[i - j][k];
    for (int i = 1; i < n; i++)ans += f[n][i];//跑n圈的总方案数目(不管最后一次跑多少圈)
    cout << ans;
    return 0;
}

P8742 [蓝桥杯 2021 省 AB] 砝码称重

题目描述

你有一架天平和 NN 个砝码, 这 NN 个砝码重量依次是 W_{1}, W_{2}, \cdots, W_{N}W1,W2,⋯,WN 。 请你计算一共可以称出多少种不同的重量?

注意砝码可以放在天平两边。

输入格式

输入的第一行包含一个整数 NN

第二行包含 NN 个整数: W_{1}, W_{2}, W_{3}, \cdots, W_{N}W1,W2,W3,⋯,WN

输出格式

输出一个整数代表答案。

输入输出样例

输入 #1复制

3

1 4 6

输出 #1复制

10

说明/提示

【样例说明】

能称出的 10 种重量是: 1 、 2 、 3 、 4 、 5 、 6 、 7 、 9 、 10 、 111、2、3、4、5、6、7、9、10、11 。

\begin{aligned} &1=1 \\ &2=6-4(\text { 天平一边放 } 6, \text { 另一边放 4) } \\ &3=4-1 \\ &4=4 \\ &5=6-1 \\ &6=6 \\ &7=1+6 \\ &9=4+6-1 \\ &10=4+6 \\ &11=1+4+6 \end{aligned}1=12=6−4( 天平一边放 6, 另一边放 4) 3=4−14=45=6−16=67=1+69=4+6−110=4+611=1+4+6

【评测用例规模与约定】

对于 50 \%50% 的评测用例, 1 \leq N \leq 151≤N≤15 。

对于所有评测用例, 1 \leq N \leq 100, N1≤N≤100,N 个砝码总重不超过 10^5105。

蓝桥杯 2021 第一轮省赛 A 组 F 题(B 组 G 题)。

砝码有两种放置方法:1.放右边:f[j]=max(f[j],f[j-w[i]]);
2.放左边:f[j]=max(f[j],f[j+w[i]]);
其中f[j]表示重量j能否称出来,w[i]表示每个砝码的重量。
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5+3;
long long n, f[maxn], ans,w[103];
int main()
{
    cin >> n;
    for (ll i = 1; i <= n; i++)cin >> w[i];
    f[0] = 1;
    for (ll i = 1; i <= n; i++)
        for (ll j = maxn; j >= w[i]; j--)
            f[j] = max(f[j], f[j- w[i]]);
    for (ll i = 1; i <= n; i++)
        for (ll j = 1; j < maxn - w[i]; j++)
            f[j] = max(f[j], f[j + w[i]]);
    for (ll i = 1; i <= maxn; i++)ans += f[i];//计数
    cout << ans<

P1959 遗址

题目描述

很久很久以前有一座寺庙,从上往下看寺庙的形状正好是一个正方形,由 44 个角上竖立的圆柱搭建而成。现在圆柱都倒塌了,只在地上留下圆形的痕迹,可是现在地上有很多这样的痕迹,专家说一定是最大的那个。

写一个程序,给出圆柱的坐标,找出由 44 个圆柱构成的最大的正方形,因为这就是寺庙的位置,要求计算出最大的面积。注意正方形的边不一定平行于坐标轴。

例如图有 1010 根柱子,其中 (4,2),(5,2),(5,3),(4,3)(4,2),(5,2),(5,3),(4,3) 可以形成一个正方形,(1,1),(4,0),(5,3),(2,4)(1,1),(4,0),(5,3),(2,4) 也可以,后者是其中最大的,面积为 1010。

P1796 汤姆斯的天堂梦+P1806 跑步+P8742 [蓝桥杯 2021 省 AB] 砝码称重+P1959 遗址+P8794 [蓝桥杯 2022 国 A] 环境治理_第2张图片

输入格式

第一行包含一个 N(1\leq N\leq 3000)N(1≤N≤3000),表示柱子的数量。

接下来 NN 行,每行有两个空格隔开的整数表示柱子的坐标(坐标值在 00 到 50005000 之间),柱子的位置互不相同。

输出格式

如果存在正方形,输出最大的面积,否则输出 00。

输入输出样例

输入 #1复制

10

9 4

4 3

1 1

4 2

2 4

5 8

4 0

5 3

0 5

5 2

输出 #1复制

10

说明/提示

【数据范围】

30\%30% 满足:1\leq N \leq1001≤N≤100。

60\%60% 满足:1\leq N \leq5001≤N≤500。

100\%100% 满足:1\leq N \leq30001≤N≤3000。

需要一定的数学知识,如果一个个地去枚举点会超时,找到两个点后指定一个方向来计算正方形其他点的坐标

P1959 - cyx2009 的博客 - 洛谷博客 (luogu.com.cn)

P1796 汤姆斯的天堂梦+P1806 跑步+P8742 [蓝桥杯 2021 省 AB] 砝码称重+P1959 遗址+P8794 [蓝桥杯 2022 国 A] 环境治理_第3张图片
#include
using namespace std;
bool  f[5003][5003];
int n, x[3003], y[3003],ans;
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> x[i] >> y[i];
        f[x[i]][y[i]] = 1;
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            int dx = x[i] - x[j];
            int dy = y[i] - y[j];
            int x1 = x[i] - dy;
            int x2 = x[j] - dy;
            int y1 = y[i] + dx;            
            int y2 = y[j] + dx;
            if (x1 < 0 || x1>5000 || x2 < 0 || x2>5000 || y1 < 0 || y1>5000 || y2 < 0 || y2>5000)continue;//判断下标是否合法
            if (f[x1][y1] && f[x2][y2])
            {
                ans = max(ans, dx * dx + dy * dy);
            }
        }
    }
    cout << ans << endl;
    return 0;
}

P8794 [蓝桥杯 2022 国 A] 环境治理

题目描述

LQ 国拥有 nn 个城市,从 00 到 n - 1n−1 编号,这 nn 个城市两两之间都有且仅有一条双向道路连接,这意味着任意两个城市之间都是可达的。每条道路都有一个属性 DD,表示这条道路的灰尘度。当从一个城市 A 前往另一个城市 B 时,可能存在多条路线,每条路线的灰尘度定义为这条路线所经过的所有道路的灰尘度之和,LQ 国的人都很讨厌灰尘,所以他们总会优先选择灰尘度最小的路线。

LQ 国很看重居民的出行环境,他们用一个指标 PP 来衡量 LQ 国的出行环境,PP 定义为:

P=\sum \limits_{i=0}^{n-1} \sum \limits_{j=0}^{n-1} d(i,j)P=i=0∑n−1j=0∑n−1d(i,j)

其中 d(i,j)d(i,j) 表示城市 ii 到城市 jj 之间灰尘度最小的路线对应的灰尘度的值。

为了改善出行环境,每个城市都要有所作为,当某个城市进行道路改善时,会将与这个城市直接相连的所有道路的灰尘度都减少 11,但每条道路都有一个灰尘度的下限值 LL,当灰尘度达到道路的下限值时,无论再怎么改善,道路的灰尘度也不会再减小了。

具体的计划是这样的:

  • 第 11 天,00 号城市对与其直接相连的道路环境进行改善;

  • 第 22 天,11 号城市对与其直接相连的道路环境进行改善;

……

  • 第 nn 天,n - 1n−1 号城市对与其直接相连的道路环境进行改善;

  • 第 n + 1n+1 天,00 号城市对与其直接相连的道路环境进行改善;

  • 第 n + 2n+2 天,11 号城市对与其直接相连的道路环境进行改善;

……

LQ 国想要使得 PP 指标满足 P \leq QPQ。请问最少要经过多少天之后,PP 指标可以满足 P \leq QPQ。如果在初始时就已经满足条件,则输出 00;如果永远不可能满足,则输出 -1−1。

输入格式

输入的第一行包含两个整数 n, Qn,Q,用一个空格分隔,分别表示城市个数和期望达到的 PP 指标。

接下来 nn 行,每行包含 nn 个整数,相邻两个整数之间用一个空格分隔,其中第 ii 行第 jj 列的值 D_{i,j} (D_{i,j}=D_{j,i},D_{i,i} = 0)Di,j(Di,j=Dj,i,Di,i=0) 表示城市 ii 与城市 jj 之间直接相连的那条道路的灰尘度。

接下来 nn 行,每行包含 nn 个整数,相邻两个整数之间用一个空格分隔,其中第 ii 行第 jj 列的值 L_{i,j} (L_{i,j} = L_{j,i}, L_{i,i} = 0)Li,j(Li,j=Lj,i,Li,i=0) 表示城市 ii 与城市 jj 之间直接相连的那条道路的灰尘度的下限值。

输出格式

输出一行包含一个整数表示答案。

输入输出样例

输入 #1复制

3 10

0 2 4

2 0 1

4 1 0

0 2 2

2 0 0

2 0 0

输出 #1复制

2

说明/提示

【样例说明】

初始时的图如下所示,每条边上的数字表示这条道路的灰尘度:

P1796 汤姆斯的天堂梦+P1806 跑步+P8742 [蓝桥杯 2021 省 AB] 砝码称重+P1959 遗址+P8794 [蓝桥杯 2022 国 A] 环境治理_第4张图片

此时每对顶点之间的灰尘度最小的路线对应的灰尘度为:

  • d(0, 0) = 0, d(0, 1) = 2, d(0, 2) = 3d(0,0)=0,d(0,1)=2,d(0,2)=3;

  • d(1, 0) = 2, d(1, 1) = 0, d(1, 2) = 1d(1,0)=2,d(1,1)=0,d(1,2)=1;

  • d(2, 0) = 3, d(2, 1) = 1, d(2, 2) = 0d(2,0)=3,d(2,1)=1,d(2,2)=0。

初始时的 PP 指标为 (2 + 3 + 1) \times 2 = 12(2+3+1)×2=12,不满足 P \leq Q = 10PQ=10;

第一天,00 号城市进行道路改善,改善后的图示如下:

P1796 汤姆斯的天堂梦+P1806 跑步+P8742 [蓝桥杯 2021 省 AB] 砝码称重+P1959 遗址+P8794 [蓝桥杯 2022 国 A] 环境治理_第5张图片

注意到边 (0, 2)(0,2) 的值减小了 11,但 (0, 1)(0,1) 并没有减小,因为 L_{0,1} = 2L0,1=2 ,所以 (0, 1)(0,1) 的值不可以再减小了。此时每对顶点之间的灰尘度最小的路线对应的灰尘度为:

  • d(0, 0) = 0, d(0, 1) = 2, d(0, 2) = 3d(0,0)=0,d(0,1)=2,d(0,2)=3,

  • d(1, 0) = 2, d(1, 1) = 0, d(1, 2) = 1d(1,0)=2,d(1,1)=0,d(1,2)=1,

  • d(2, 0) = 3, d(2, 1) = 1, d(2, 2) = 0d(2,0)=3,d(2,1)=1,d(2,2)=0。

此时 PP 仍为 1212。

第二天,1 号城市进行道路改善,改善后的图示如下:

P1796 汤姆斯的天堂梦+P1806 跑步+P8742 [蓝桥杯 2021 省 AB] 砝码称重+P1959 遗址+P8794 [蓝桥杯 2022 国 A] 环境治理_第6张图片

此时每对顶点之间的灰尘度最小的路线对应的灰尘度为:

  • d(0, 0) = 0, d(0, 1) = 2, d(0, 2) = 2d(0,0)=0,d(0,1)=2,d(0,2)=2,

  • d(1, 0) = 2, d(1, 1) = 0, d(1, 2) = 0d(1,0)=2,d(1,1)=0,d(1,2)=0,

  • d(2, 0) = 2, d(2, 1) = 0, d(2, 2) = 0d(2,0)=2,d(2,1)=0,d(2,2)=0。

此时的 PP 指标为 (2 + 2) \times 2 = 8 < Q(2+2)×2=8<Q,此时已经满足条件。

所以答案是 22。

【评测用例规模与约定】

  • 对于 30\%30% 的评测用例,1 \leq n \leq 101≤n≤10,0 \leq L_{i,j} \leq D_{i,j} \leq 100≤Li,jDi,j≤10;

  • 对于 60\%60% 的评测用例,1 \leq n \leq 501≤n≤50,0 \leq L_{i,j} \leq D_{i,j} \leq 10^50≤Li,jDi,j≤105;

  • 对于所有评测用例,1 \leq n \leq 1001≤n≤100,0 \leq L_{i,j} \leq D_{i,j} \leq 10^50≤Li,jDi,j≤105,0 \leq Q \leq 2^{31} - 10≤Q≤231−1。

蓝桥杯 2022 国赛 A 组 F 题。

多源最短路径采用floyed算法
#include
using namespace std;
#define N 105
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define mid (l + r >> 1)
int n, Q, l, r, ans = INF;
int D[N][N], L[N][N], dis[N][N], reduce[N];
inline int check(int x) {
    int t = x / n, P = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) 
            dis[i][j] = INF;
    for (int i = 1; i <= n; i++) 
        dis[i][i] = 0;
    for (int i = 1; i <= n; i++)
        reduce[i] = t;
    for (int i = 1; i <= x - n * t; i++)
        ++reduce[i];
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) 
            dis[i][j] = max(L[i][j], D[i][j] - reduce[i] - reduce[j]);//与每条道路都有的一个灰尘度的下限值比较取最小值
    for(int k=1;k<=n;k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++) 
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            P += dis[i][j];
    if (P <= Q) return 1;
    else return 0;
}

signed main() {
    cin >> n >> Q;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            cin >> D[i][j];
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            cin >> L[i][j];
    l = 0, r = INF;
    while (l <= r) {
        if (check(mid)) ans = min(ans, mid), r = mid - 1;
        else l = mid + 1;
    }
    if (ans == INF) printf("-1");
    else printf("%lld", ans);
    return 0;
}

你可能感兴趣的:(算法学习,算法,动态规划,图论)