每日算法 - day 32

每日算法

those times when you get up early and you work hard; those times when you stay up late and you work hard; those times when don’t feel like working — you’re too tired, you don’t want to push yourself — but you do it anyway. That is actually the dream. That’s the dream. It’s not the destination, it’s the journey. And if you guys can understand that, what you’ll see happen is that you won’t accomplish your dreams, your dreams won’t come true, something greater will. mamba out


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

2020.3.18


luogu- p1180 驾车旅游

对于条件过多的搜索,一定要先跟根据条件列出搜索框架,即在什么时候搜索树可能产生分支,再填入与题目意义相符合的参数,最后根据条件进行剪枝,记忆化等,优化操作,写好框架之后一定认真处理细节

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <vector>


using namespace std;

int dis ,  cnt;
double maxtank , milefare , startfare , half;
struct node{
    int dis;
    double fare;
};

vector<node> v;

double ans;
/* 
   oil :   当前剩余油量
   cost:   表示当前花费
   k :      下一个加油站的id
*/ 
void dfs(double oil, double cost,int k)
{
    if(cost > ans)return;
    if(k == cnt)
    {
        ans = min(cost,ans);
        return;
    }
    // 判断以下能不能到达下一个加油站 
    if(oil * milefare >= v[k + 1].dis - v[k].dis)
    {
        if(oil >= half)
        {
            dfs(oil - (v[k + 1].dis - v[k].dis) / milefare,cost,k + 1);
        }else{ // 可以加 也可以不加 
            dfs(oil - (v[k + 1].dis - v[k].dis) / milefare,cost,k + 1);
            dfs(maxtank - (v[k + 1].dis - v[k].dis) / milefare,cost + 20 + (maxtank - oil) * v[k].fare,k + 1); 
        }
    }else{ //必须加 
        dfs(maxtank - (v[k + 1].dis - v[k].dis) / milefare,cost + 20 + (maxtank - oil) * v[k].fare,k + 1); 
    }
}
void input()
{
    cin >> dis;
    cin >> maxtank >> milefare >> startfare;
    cin >> cnt;
    half = maxtank / 2; //一半得油量 
    int a;double b;
    for(int i = 0; i < cnt ; i++)
    {
        cin >> a >> b;
        ans += 20 + maxtank * b;
        v.push_back({a , b});
    }
    v.push_back({dis,0}); //加入终点 
}
int main()
{
    input();
    dfs(maxtank - v[0].dis / milefare,startfare,0);
    printf("%.1f",ans); 
    return 0;   
} 

luogu -p1120 导弹拦截

暴力做法 \(O(n^2)\)


#include <iostream>
#include <cmath>
using namespace std;

int a[100000 + 1];
int dp[100000 + 1];
int main()
{
    int n = 1;
    //输入
    while (cin >> a[n])n++;n--;
    int ans = 0, nss = 0;
    int cnt;
    cnt = 1; dp[1] = a[1];

    for(int i = 2; i <= n; i++)
    {
        //如果dp[cnt] 大于 a[]中的任意一个数就将其添加到dp中得到一个递减的序列
        if (dp[cnt] >= a[i])
        {
            dp[++cnt] = a[i];
        }
        //如果就遍历dp[j]找到第一个比a[i]小的 并将其替换掉
        else {
            for (int j = 1;; j++)
            {
                if (dp[j] < a[i])
                {
                    dp[j] = a[i];
                    break;
                }
            }
        }
    }
    cout << cnt << endl;
    cnt = 1, dp[1] = a[1];
    for (int i = 2; i <= n; i++)
    {
        if (dp[cnt] < a[i])
        {
            dp[++cnt] = a[i];
        }
        else {
            for (int j = 1;; j++)
            {
                if (dp[j] >= a[i])
                {
                    dp[j] = a[i];
                    break;
                }
            }
        }
    }
    cout << cnt << endl;
    system("pause");
    return 0;
}

数学做法 时间复杂度\(O(nlogn)\)

狄尔沃斯定理(Dilworth's theorem)
先挖个坑吧 数论的东西等回头有时间在学

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
using namespace std;
const int N = 100005;
int n , a[N] , s[N] , j[N];
int ss = 0 , jj = 0;
int main()
{
    int h , cnt = 1;
    while(scanf("%d",&h) != EOF)
    {
        a[cnt++] = h;
    }cnt--;
    // 求出来一个最长下降子序列 和最长上升子序列
    s[0] = 0x3f3f3f3f;
    for(int i = 1;i <= cnt;i ++)
    {
        if(s[ss] >= a[i])
        {
            s[ss + 1] = a[i];
            ss++;
        }else{
            int l = 0, r = ss;
            while(l < r)
            {
                int mid = l + r >> 1;
                if(s[mid] >= a[i])l = mid + 1;
                else r = mid;
            }
            if(l != 0)s[l] = a[i];
        }
    }
    cout << ss << endl;
    for(int i = 1;i <= cnt;i ++)
    {
        if(j[jj] < a[i])
        {
            j[jj + 1] = a[i];
            jj ++;
        }else{
            int l = 0, r = jj;
            while(l < r)
            {
                int mid = l + r >> 1;
                if(j[mid] >= a[i])r = mid;
                else l = mid + 1;
            }
            j[l] = a[i];
        }
    }
    cout << jj << endl;
    return 0;
} 

P1090 合并果子 / [USACO06NOV]Fence Repair G

题意分析:

众所周知合并果子是一个经典的贪心问题 ,但是我还没有认真练习过这道题,今天来好好剖析以下这道题目。

既然是贪心的思想: 那么就首先要将问题分解为子问题,然后着眼于子问题的最优解,最后将所有子问题的最优解汇总即可

n 堆果子一定会经过 n - 1次合并,而每次消耗的体力之和为两堆果子的重量 , 举个栗子

我们拿样例 n = 3 举例

1 2 9分别为三堆果子的数量。
我们分别采用两种极端的方法:

  1. 先将最大的和最大的合并:
    第一次合并 : 1 11 耗费体力 : 11
    第二次合并 : 12 耗费体力 : 11 + 12 = 23
  2. 先将最小的两堆合并
    第一次合并 : 3 9 耗费体力 : 3
    第二次合并 : 12 耗费体力 : 3 + 12 = 15

其实我们已经可以发现,我们每次挑选最大的指挥使得我们再下一次合并时增加我们的体力消耗,于是我们应该尽可能的避免这种消耗

也就是说我们最终采用的贪心策略实际上就是每次取出最小的两个进行合并,合并完之后再将其合并值放入,在进行重复操作,相信大家都想到了 堆 和 赫夫曼树。赫夫曼树就不说了 ,已经忘记怎么写了 hhh 在这里采用堆的形式解决也就是STL 中的优先队列

最后成功让这道题变成水题。。。QAQ

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <queue>

using namespace std;

// 申请小顶堆 
priority_queue<int,vector<int>,greater<int> > q;
int n ; 
int main()
{
    cin >> n;
    int x;
    for(int i = 0;i < n ;i ++)
    {
        cin >> x;
        q.push(x);
    }
    long long ans = 0; 
    while(q.size() >= 2)
    {
        int a = q.top();q.pop();
        int b = q.top();q.pop();
        ans += a + b;
        q.push(a + b);
    }
    cout << ans << endl;
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/wlw-x/p/12519536.html