算法题目记录

1.最短距离 

 

题目简化:

明确问题 + 算法提示:

1.如何判断同类之间的最短距离为0 ---> 并查集+路径压缩

2.如何存储任意两类的距离 ---> 邻接矩阵存储无向图

3.如何表示每个点属于哪一类 ---> 用数组id[节点]存储属于哪一类

4.如何算出任意两类之间的最短距离 ---> 最短路问题:Floyd算法(多源汇最短路,多个起点)[动态规划]

详细思路:

并查集+路径压缩

int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

Floyd算法

for (int t = 1; t <= k; t ++)
{
    for (int i = 1; i <= k; i ++)
    {
        for (int j = 1; j <= k; j ++)
        {
            d[i][j] = min(d[i][j], d[i][t] + d[t][j]);
        }
    }
}

代码: 

#include <iostream>
#include <cstring>

using namespace std;

const int N = 1e5 + 10, M = 510, INF = 0x3f3f3f3f;
int p[N], id[N];
int d[M][M]; //两个类之间的距离
int n, m, k;

int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}
bool check()
{
    for (int i = 2; i <= n; i ++)
        if (id[i] == id[i - 1] && find(i) != find(i - 1))
            return false;
    return true;        
}
int main()
{

    cin >> n >> m >> k;
    for (int i = 1; i <= n; i ++) p[i] = i;
   
    for (int i = 1, j = 1; i <= k; i ++) 
    {
        int c;
        cin >> c;
        while (c --) id[j ++] = i;
    }
    
    memset(d, 0x3f, sizeof d);
    for (int i = 1; i <= k; i ++ ) d[i][i] = 0;
    
    for (int i = 1; i <= m; i ++)
    {
        int u, v, x;
        cin >> u >> v >> x;
        if (!x) p[find(u)] = find(v);
        int a = id[u], b = id[v];
        
        d[a][b] = d[b][a] = min(d[a][b], x);
    }
    if (!check()) puts("No");
    else
    {
        puts("Yes");
        for (int t = 1; t <= k; t ++)
        {
            for (int i = 1; i <= k; i ++)
            {
                for (int j = 1; j <= k; j ++)
                {
                    d[i][j] = min(d[i][j], d[i][t] + d[t][j]);
                }
            }
        }
        
        for (int i = 1; i <= k; i ++)
        {
            for (int j = 1; j <= k; j ++)
            {
                if (d[i][j] == INF) d[i][j] = -1;
                cout << d[i][j] << ' ';
            }
            cout << endl;
        }
    }
}


2.奶牛报数

题目简化:

        将这n头牛按顺时针围成一个圈,然后选定一头牛开始从1报数,所有的牛报完数,每一头牛都有相应的报的数字,当报到的数落在[l, r)区间中,则表示该牛被选中制作牛肉

        限制条件:所选牛的重量总和最大且第一头牛所报的数尽量小的方案

        求:第一头牛所报的数

明确问题 + 算法提示:

        1.如何表示按顺时针围成一圈的牛?---> 破环成链

        2.如何算出报数在区间内牛的重量总和?---> 区间和:前缀和

        3.如何算出第一头牛所报的数? ---> 通过第i头牛报的数,算出第1头牛所报的数

图解分析: 

代码: 

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10;
int n, l, r;
int a[2 * N], s[2 * N];

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i ++)
    {
        cin >> a[i];
        a[i + n] = a[i];
    }
    
    //求前缀和
    for (int i = 1; i <= 2 * n; i ++) s[i] = s[i - 1] + a[i];
    
    cin >> l >> r;
    
    int len = r - l, res = -1, ans = 0;
    
    for (int i = 1; i <= 2 * n - len; i ++)
    {
        int sum = s[i + len - 1] - s[i - 1], idx = l - i + 1;
        while (idx < 1) idx += n;
        if (sum > ans || sum == ans && idx < res)
        {
            res = idx;
            ans = sum;
        }
    }
    cout << res << endl;
}


3.机器人跳跃问题

题目简化:

机器人初始有能量值e,机器人需要跳跃n个建筑,每个建筑有对应的高度,第i个建筑的高度

为h[i],机器人每次跳跃当前建筑,所花费的代价为e - h[i](即当e > h[i]时,能量增加e - h[i];当e < h[i]时,能量减少e - h[i]), 在每次跳跃后要保证能量值不能为负数

图示分析:

算法:递推 + 二分查找 

代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10;
int n, h[N];

bool judge(int e)
{
    for (int i = 1; i <= n; i ++)
    {
        e = 2 * e - h[i];
        if (e < 0) return  false;
        if (e >= N) return true;
    }
    return true;
}
int main()
{
    scanf ("%d", &n);
    for (int i = 1; i <= n; i ++) scanf ("%d", &h[i]);
    
    int l = 0, r = N;
    while (l < r)
    {
        int mid = (l + r) / 2;
        if (judge(mid)) r = mid;
        else l = mid + 1; 
    }
    
    cout << l << endl;
    return 0;
}

注意:题目均来自AcWing

所有笔记总结目录-CSDN博客

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值