CF1741G(状态压缩,DP)

Problem – G – Codeforces

题意

给一个无向连通图,有 \(f\) 个朋友在节点1,每个人的家在 \(h_i\) ,其中有 \(k(k \le 6)\)个朋友没有车,有车的朋友可以开车载任意数量的没车且家在有车朋友的回家的最短路上的没车朋友回家。问最后无法被开车送回的朋友的最小数量。

思路

\(k\) 的数量很小,可以考虑将朋友送到每个节点的状态压入 \(k\) 个bit位中。然后问题就变成对有车朋友最大化可行方案的bit位中1的个数。这个做一个可行性dp。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<bitset>
#include<queue>
#include<map>
#include<stack>
#include<string>
#include<random>
#include<cassert>
#include<functional>
#include<iomanip>
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3fll
#define endl '\n'
#define ll long long
// #define int long long
#define SZ(x) (int)x.size()
#define rep(i,a,n) for(int i = (a);i <= (n);i++)
#define dec(i,n,a) for(int i = (n);i >= (a);i--)
using namespace std;
using PII = pair<int, int>;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
const int N =10 + 2e5 ,mod=1e9 + 7;
/* 
    联通无向图, 起点1,朋友都在1,第i个朋友要去h_i
    k <= 6 no car 。有车的朋友可以让他们搭便车,但只能沿着最短路走
    输出最小走路的朋友
    最多n方的可能状态,对每一个有车f考虑,使得或值最大
    f[i][mask] |= f[i - 1][j] if(can find t | j == mask)
    
 */
void solve()
{    
    int n, m; cin >> n >> m;
    vector<vector<int>> adj(n + 1);
    rep(i, 1, m) {
        int u, v; cin >> u >> v;
        adj[u].emplace_back(v);
        adj[v].emplace_back(u);
    }    
    int fn; cin >> fn;
    vector<int> h(fn + 1);
    rep(i, 1, fn) cin >> h[i];
    int k; cin >> k;
    vector<int> p(k + 1);
    rep(i, 1, k) cin >> p[i];
    
    vector<int> state[n + 1];
    vector<vector<bool>> ex(n + 1, vector<bool>(1 << k));
    {
        queue<PII> q; q.push({1, 0});
        vector<bool> st(n + 1); 
        vector<int> dis(n + 1, -1); dis[1] = 0;
        state[1].push_back(0);
        ex[1][0] = 1;

        auto chk = [&](int x) {
            int ans = 0;
            rep(i, 1, k) if(x == h[p[i]]) ans |= (1 << (i - 1));
            return ans;
        };
        while(!q.empty()) {
            auto [u, fa] = q.front(); q.pop();
            if(~fa and dis[fa] + 1 == dis[u]) {
                int where = chk(u);
                for(auto x : state[fa]) if(!ex[u][where | x])
                    state[u].push_back(where | x), ex[u][where | x] = 1;
            }
            if(st[u]) continue;
            st[u] = 1;
            for(int v : adj[u]) if(v != fa) {
                if(dis[v] == -1) dis[v] = dis[u] + 1;
                q.push({v, u});
            }
        }
    }
    int ans = 0;
    {
        // f[i][mask] |= f[i - 1][j] if(can find t | j == mask)
        vector<vector<int>> f(fn - k + 1, vector<int>(1 << k, 0));
        f[0][0] = 1;
        int cur = 1;
        rep(i, 1, fn) {
            bool jump = 0;
            rep(j, 1, k) if(p[j] == i) jump = 1;
            if(jump) continue;

            rep(mask, 0, (1 << k) - 1) {
                for(auto t : state[h[i]]) {
                    rep(j, 0, (1 << k) - 1) if(mask == (t | j)) {
                        f[cur][mask] |= f[cur - 1][j];
                    }
                }
            }
            cur ++;
        }
        rep(mask, 0, (1 << k) - 1) if(f[fn - k][mask]) 
            ans = max(ans, __builtin_popcount(mask));
    }
    cout << k - ans << endl;

}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}

原文地址:http://www.cnblogs.com/Mxrush/p/16797001.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性