Daliy Algorithm (dp,LCA,ST)-- day 85

Nothing to fear


种一棵树最好的时间是十年前,其次是现在!

那些你早出晚归付出的刻苦努力,你不想训练,当你觉的太累了但还是要咬牙坚持的时候,那就是在追逐梦想,不要在意终点有什么,要享受路途的过程,或许你不能成就梦想,但一定会有更伟大的事情随之而来。 mamba out~

2020.5.28


人一我十,人十我百,追逐青春的梦想,怀着自信的心,永不言弃!

LC-983 最低票价

  1. 首先我们设计状态表示:dp[i] 从第i天到一年的最后一天结束我们需要花的钱,
    由于一张通行证可以让我们在[接下来]的若干天进行旅行,所以我们选择[从后往前倒着进行动态规划]

  2. 加入了贪心思想
    2.1如果这一天不是必须出行的日期,那我们可以贪心的选择不买。并且通行证购买的越晚越好
    dp[i] = dp[i+1]

2.2如果这一天必须出行,我们可以选择买1 7 30天的通行证如果我们在第 j 天购买了通行证,那么接下来的 j - 1天,我们都不需要再购买通行证,只需要在第 i + j 天及以后即可,因此

dp[i] = min{cost[j] + dp[i + j]} , j属于{1 , 7 , 13};

class Solution {
    vector<int> costs;
    unordered_set<int> dayset;
    int book[366] = {0};
public:
    int mincostTickets(vector<int>& days, vector<int>& costs) {
            this->costs = costs;
            for(int d : days)
            {
                dayset.insert(d);
            }
            memset(book , -1 , sizeof book);
            return dp(1);
    }
    int dp(int i)
    {
        if(i > 365)return 0;
        if(book[i] != -1)return book[i];
        if(dayset.count(i))
        {
            book[i] = min(min(dp(i+1) + costs[0],dp(i+7) + costs[1]),dp(i+30) + costs[2]);
        }else return dp(i+1);
        return book[i];
    }
};

LG-P1364 医院设置

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>

using namespace std;
const int N = 101;

int g[N][N] , w[N] , n;
void floyd()
{
    for(int k = 1;k <= n ;k ++)
    {
        for(int i = 1;i <= n ;i ++)
        {
            for(int j = 1;j <= n ;j ++)
            {
                if(g[i][k] + g[k][j] < g[i][j])
                {
                     g[i][j] = g[i][k] + g[k][j];
                }   
            }
        }
    }
}
int main()
{
    int  b , c;
    memset(g , 0x3f3f3f3f , sizeof g);
    cin >> n;
    for(int i = 1;i <= n ;i ++)
    {
        cin >> w[i] >> b >> c;
        if(b)g[i][b] = 1,g[b][i] = 1;
        if(c)g[i][c] = 1,g[c][i] = 1;
    }
    floyd();

    int ans = 0x3f3f3f3f;
    for(int i = 1;i <= n ;i ++)
    {
        int sum = 0;
        for(int j = 1;j <= n;j ++)
        {
            if(i != j)
            sum += g[i][j] * w[j];
        }
        ans = min(ans , sum);
    }
    cout << ans << endl;
    return 0;
}

LG-P3884 [JLOI2009]二叉树问题

自己写了一个暴力LCA 时间复杂度为O(n)
由于这里只查询一次所以完全可以承受但是如果数据量过大的话就需要倍增优化了

思路:
需要提前记录每个人结点的父亲节点
实际上就是找两个结点到其最近祖先的距离

  1. 设置两个当前结点 unow , vnow 初始化位其初始节点
  2. 首先分析一共存在多少情况
  3. 通过分析大致才行只要满足unow 和 vnow的当前深度相同
    且满足(f[unow] == f[vnow]) || (vnow == unow)
void BF_LCA(int u,int v)
{
    int us = 0, vs = 0 ,unow = u,vnow = v;
    while(1)
    {
        //printf("当前 u = %d v = %d \n",unow,vnow);
        int ud = depth[unow],vd = depth[vnow];
        if(ud == vd) // 深度相同进行检查
        {
            if(vnow == unow)break;
            else if(f[unow] == f[vnow]) // 父亲相同
            {
                us++;vs++;break;
            }else{
                vnow = f[vnow];vs++;
            }
        }
        // 优先利用深度较小的结点去追赶深度较深的结点
        if(ud > vd){
            unow = f[unow];
            us++;continue;
        }
        if(ud < vd) {
            vnow = f[vnow];
            vs++;continue;
        }
    }
}

完整代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>

using namespace std;
const int N = 10005;
int n;
int e[N][N] , f[N];
int depth[N], cnt[N] , MAX_dep = 0,MAX_wei = 0;
bool vis[N] = {0};
void dfs(int now ,int dep)
{
    depth[now] = dep;
    MAX_dep = max(MAX_dep , dep);
    cnt[dep]++;
    MAX_wei = max(MAX_wei, cnt[dep]);
    for(int i = 1;i <= n ;i ++)
    {
        if(vis[i] == false && e[now][i] == 1)
        {
            vis[i] = 1;
            dfs(i , dep + 1);
        }
    }
}   
/*
 实际上就是找两个结点到其最近祖先的距离
1. 设置两个当前结点 unow , vnow 初始化位其初始节点
2. 首先分析一共存在多少情况
3. 通过分析大致才行只要满足unow 和 vnow的当前深度相同
   且满足(f[unow] == f[vnow]) || (vnow == unow)
*/
void BF_LCA(int u,int v)
{
    int us = 0, vs = 0;
    int unow = u,vnow = v;
    while(1)
    {
        //printf("当前 u = %d v = %d \n",unow,vnow);
        int ud = depth[unow],vd = depth[vnow];
        if(ud == vd) // 深度相同进行检查
        {
            if(vnow == unow)break;
            else if(f[unow] == f[vnow]) // 父亲相同
            {
                us++;vs++;break;
            }else{
                vnow = f[vnow];vs++;
            }
        }
        // 优先利用深度较小的结点去追赶深度较深的结点
        if(ud > vd)
        {
            unow = f[unow];
            us++;continue;
        }
        if(ud < vd) 
        {
            vnow = f[vnow];
            vs++;continue;
        }
    }
    //cout << us << " " << vs << endl;
    cout << us * 2 + vs << endl;
}
int main()
{
    cin >> n;
    int a, b;
    int u , v;
    for(int i = 1;i <= n - 1;i ++)
    {
        cin >> a >> b;
        e[a][b] = 1;
        f[b] = a; // 设置每个儿子的爹
    }
    cin >> u >> v;
    vis[1] = 1;
    dfs(1 , 1);
    cout << MAX_dep << endl;
    cout << MAX_wei << endl;
    findFa(u , v);
    return 0;
}

LG-P2880 [USACO07JAN]Balanced Lineup G

ST表

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>

using namespace std;
const int N = 50005;
int n , m;
int f[N][35] , a[N] , g[N][35];
void ST_prework()
{
    for(int i = 1;i <= n ;i ++) f[i][0] = a[i] , g[i][0] = a[i];    
    int t = log(n) / log(2) + 1;
    for(int j = 1;j < t ;j ++)
    {
        for(int i = 1;i <= n - (1 << j) + 1;i ++)
        {
            f[i][j] = max(f[i][j-1],f[i + (1 << (j - 1))][j-1]);
            g[i][j] = min(g[i][j-1],g[i + (1 << (j - 1))][j-1]);
        }
    }
}
int ST_query(int l,int r)
{
    int k = log(r - l + 1) / log(2);
    int x = max(f[l][k] , f[r - (1 << k) + 1][k]);
    int y = min(g[l][k] , g[r - (1 << k) + 1][k]);
    return abs(x - y);
}
int main()
{
    cin >> n >> m;
    for(int i = 1;i <= n ;i ++)cin >> a[i];
    ST_prework();
    while(m --)
    {
        int l , r;
        cin >> l >> r;
        cout << ST_query( l ,r) << endl;
    }
    return 0;
}
posted @ 2020-05-29 09:29  _starsky  阅读(166)  评论(0编辑  收藏  举报