ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021CCPC女生赛C. 连锁商店 状压DP

2021-11-02 13:31:42  阅读:268  来源: 互联网

标签:ve int 状压 50 st 2021CCPC num 连锁商店 dp


原题链接:https://codeforces.ml/gym/103389/problem/C

目录

题意

有n个景点,下标代表高度,接着又m条路线,一定从低到高,每个景点都属于不同公司,每个公司都有不同的红包政策,但每个公司的红包只能领一个,问从1到 [ 1 , n ] [1,n] [1,n]所有景点能领到的最多红包金额是多少。

分析

乍一看这题的n是36,好像没法状压,其实仔细看可以发现,如果一个公司只有一个景点,那么可以直接拿红包,如果一个公司有超过一个景点,那么可以考虑进状态里,也不会超过18个状态。

这样题目就简单很多了,我们直接从小到大去转移状态, O ( N 2 ) O(N^2) O(N2)枚举两点, O ( 2 18 ) O(2^{18}) O(218)枚举状态,总复杂度在 O ( N 2 2 N 2 ) O(N^{2}2^{\frac{N}{2}}) O(N222N​)。在转移状态的时候分类讨论一下就可以了。注意第一个点初始化时也要分类讨论。

Code

//
// Created by kaka0320 on 2021/11/1.
//
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
typedef pair<ll, ll> pii;
int c[50], w[50], vis[50], id[50], rnk[50];
vector<int> ve[50];
int dp[50][1<<18];
int g[50][50];
void solve() {
    int n, m; cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> c[i], ve[c[i]].push_back(i);
    for (int i = 1; i <= n; i++) cin >> w[i];
    for (int i = 1; i <= m; i++) {
        int u, v; cin >> u >> v;
        g[u][v] = 1;
    }
    int num = 0;
    for (int i = 1; i <= n; i++) {
        if (ve[i].empty()) continue;
        if (ve[i].size() == 1) vis[ve[i][0]] = 1;//1类集合,可全部取
        else {
            id[num] = i;
            rnk[i] = num;
            num++;
        }
    }
    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (i != j) g[i][j] |= (g[i][k] & g[k][j]);
            }
        }
    }
    if (vis[1]) dp[1][0] = w[c[1]];
    else dp[1][1<<rnk[c[1]]] = w[c[1]];
    for (int u = 1; u <= n; u++) {
        for (int st = 0; st < 1 << num; st++) {
            for (int v = 1; v <= n; v++) {
                if (!g[u][v]) continue;
                if (vis[v]) {
                    dp[v][st] = max(dp[v][st], dp[u][st] + w[c[v]]);
                } else {
                    if (!(st >> rnk[c[v]] & 1)) {
                        dp[v][st | (1 << rnk[c[v]])] = max(dp[v][st | (1 << rnk[c[v]])], dp[u][st] + w[c[v]]);
                    }
                }
            }

        }
    }
    for (int i = 1; i <= n; i++) {
        int ma = 0;
        for (int st = 0; st < 1 << num; st++) ma = max(ma, dp[i][st]);
        cout << ma << endl;
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif

#ifdef ACM_LOCAL
    auto start = clock();
#endif
    int t = 1;
//    cin >> t;
    while(t--) solve();
#ifdef ACM_LOCAL
    auto end = clock();
    cerr << "Run Time: " << double(end-start) / CLOCKS_PER_SEC << "s" << endl;
#endif
    return 0;
}

标签:ve,int,状压,50,st,2021CCPC,num,连锁商店,dp
来源: https://blog.csdn.net/kaka03200/article/details/121098298

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有