• 2021暑期个人赛2补题 (待补充)


    暑期个人赛2补题

    D - Kefa and Dishes

    CodeForces - 580D

    状态压缩dp

    思路:看数据范围可以猜出是状态压缩dp,n和m最多18,所以我们用一个20位的二进制数来表示所有状态,f[i, j]表示此时的状态是i且最后吃的菜是j,那么接下来来考虑转移。对于每个f[i, j],我们遍历i的二进制位,假如此时j的那一位是1即这个状态是已经吃了j了,那么说明是一个合法状态,可以转移。

    然后考虑可以转移给哪些状态。之后吃的一定是还没有吃过的菜,所以我们就去遍历所有菜,找到一个没吃菜k,然后将f[i, j]转移过去。方程:

    f[i ^ (1 << k), k] = max(f[i ^ (1 << k), k], f[i, j] + w[j, k] + a[k])

    最后因为我们只需要吃m道菜,遍历所有状态的i,找到符合的取一个max。

    不要忘记初始化,f[1 << i, i]表示吃了第i道菜,它应该等于第i道菜的幸福值。

    code
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long LL;
    
    int n, m, k;
    int a[20];
    int w[20][20];
    LL f[1 << 20][20];
    LL ans;
    
    int lowbit(int x)
    {
        return x & -x;
    }
    
    int cal(int u)
    {
        int cnt = 0;
        while (u)
        {
            cnt ++ ;
            u -= lowbit(u);
        }
        
        return cnt;
    }
    
    int main()
    {
        cin >> n >> m >> k;
        for (int i = 1; i <= n; i ++ ) cin >> a[i];
        while (k -- )
        {
            int x, y, c;
            cin >> x >> y >> c;
            w[x][y] = c;
        }
        //cout << w[0][1] << ' ' << w[3][2] << endl;
        for (int i = 1; i <= n; i ++ ) f[1 << i][i] = a[i];//初始化
        n ++ ;
        for (int i = 1; i < (1 << n); i ++ )
            for (int j = 1; j <= n; j ++ )
                if ((i >> j) & 1)//i状态确实吃了第j道菜即合法状态
                {
                    for (int k = 0; k < n; k ++ )
                        if (((i >> k) & 1) == 0)//找到一个i状态下还没吃的
                            f[i ^ (1 << k)][k] = max(f[i ^ (1 << k)][k], f[i][j] + w[j][k] + a[k]);
                }
    
        for (int i = 1; i < (1 << n); i ++ )
            if (cal(i) == m)//看状态i是不是有m个1即是不是吃了m道菜
            {
                for (int op = 0; op < n; op ++ )
                    ans = max(ans, f[i][op]);
            }
            
        cout << ans << endl;
        
        return 0;
    }
    
    

    F - Vacations

    CodeForces - 698A

    贪心 / 线性dp都能做

    1.贪心做法

    我们从头到尾遍历,能不休息就不休息。假设第i天可以不休息,接下来分类讨论:

    1. i + 1 天是休息日 那么我们如果不让它休息的话,结果一定更优
    2. i + 1 天和第i天活动一样,因为我们不能连续两天都工作一样的,所以这两天我们一定可以挑出一天来工作,那么以我们上述贪心策略来看,不会影响到最优解。
    3. i + 1 天和第i天活动不一样,那么既然可以不休息,那么不休息一定会有更优的答案。

    至此,贪心思路正确性证明结束,线性扫描一下即可。

    code
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 110;
    
    int a[N];
    int ans;
    int n;
    
    int main()
    {
        cin >> n;
        for (int i = 1; i <= n; i ++ ) cin >> a[i];
        
        for (int i = 1; i <= n; i ++ )//遍历一遍
        {
            if (!a[i]) ans ++ ;//如果是休息日,就休息
            else if (a[i] == 1)//如果是活动1
            {
                if (a[i + 1] == 3) a[i + 1] = 2;//后面如果是3,那么就变成2
                else if (a[i + 1] == 1) a[i + 1] = 0;//如果也是1,那么i+1天就休息
                continue;
            }
            if (a[i] == 2)
            {
                if (a[i + 1] == 3) a[i + 1] = 1;
                else if (a[i + 1] == 2) a[i + 1] = 0;
            }
        }
        
        //for (int i = 1; i <= n; i ++ ) cout << a[i] << ' ';
        //puts("");
        
        cout << ans << endl;
        
        return 0;
    }
    
    2.线性dp

    f[i, j]表示第i天的状态是j的时候需要休息的最少的天数

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 110;
    
    int n;
    int f[N][4];
    int a[N];
    
    int main()
    {
        cin >> n;
        for (int i = 1; i <= n; i ++ ) cin >> a[i];
        
        memset(f, 0x3f, sizeof f);
        f[0][0] = f[0][1] = f[0][2] = 0;
        
        for (int i = 1; i <= n; i ++ )
        {
            f[i][0] = min(f[i - 1][0], f[i - 1][1]);
            f[i][0] = min(f[i][0], f[i - 1][2]);
            f[i][0] ++ ;
            
            if (a[i] == 1)
                f[i][1] = min(f[i - 1][0], f[i - 1][2]);
            else if (a[i] == 2) 
                f[i][2] = min(f[i - 1][0], f[i - 1][1]);
            else if (a[i] == 3)
            {
                f[i][1] = min(f[i - 1][0], f[i - 1][2]);
                f[i][2] = min(f[i - 1][0], f[i - 1][1]);
            }
        }
        
        //cout << f[1][2] << endl;
        //cout << f[2][2] << endl;
        
        int ans = min(f[n][0], f[n][1]);
        ans = min(ans, f[n][2]);
        cout << ans << endl;
        
        return 0;
    }
    

    L - Maximum path

    CodeForces - 762D

  • 相关阅读:
    Tomcat应用中post方式传参数长度限制
    关于动态生成data组件
    H5 App开发用WeX5垃圾 试用一周,我果断放弃了wex5
    windowDialog销毁页面的问题
    WeX5之xid相关API
    ADB工具 获取ROOT权限及复制文件方法
    Android中使用am命令实现在命令行启动程序详解
    SQLite加密的方法(c#)
    C# Winform中如何让PictureBox的背景透明
    Android Camera API2中采用CameraMetadata用于从APP到HAL的参数交互
  • 原文地址:https://www.cnblogs.com/scl0725/p/15088163.html
Copyright © 2020-2023  润新知