Codeforces Round #826 (Div. 3) G. Kirill and Company

题目链接

思路:

观察这个 k ≤ 6 k\leq6 k6,我们是应该想到状态压缩的。准确的说往状压 d p dp dp考虑。
我们定义 d p [ i ] [ j ] dp[i][j] dp[i][j]:从起点走到 i i i,可带人的状态为 j j j
题目要求了最短路,那么我们选择 b f s bfs bfs一层一层去扩展,是可以保证最短路的。
跑完之后我们做个简单的背包统计一下最多可以带的人即可。

code:

#define D(x) cout << "BUG:  " << (x) << '\n';
#define DD(x, y) cout << "BUG:  " << (x) << "  " << (y) << '\n';
#define rep(i, x, y) for(int i = (x); i <= (y); i++)
#define per(i, x, y) for(int i = (x); i >= (y); i--)
#define INF 0x3f3f3f3f3f3f3f3fll
#define inf 0x3f3f3f3f
#define sqr(x) ((x) * (x))
#define all(x) (x).begin(), (x).end()
#define pb push_back
#define fi first 
#define se second
typedef unsigned long long ULL;
typedef pair<int, int> pii;

template <typename T> void inline read(T& x) {
    T f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}
//----------------------------------------------------------------------------------------//

const int N = 1e4 + 10, M = N * 2, mod = 998244353;

vector<int> G[N];
bool vis[N];
int n, m, f, h[N], k, p[7];
int dp[N][1 << 7]; 
//dp[i][j]:从1出发到i带的人状态为j
signed main() {
#ifdef JANGYI
    freopen("input.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    int T; read(T);
    while(T--) {
        read(n), read(m);
        rep(i, 0, n) G[i].clear(), vis[i] = 0;
        rep(i, 0, n) memset(dp[i], 0, sizeof dp[i]);
        rep(i, 1, m) {
            int u, v; 
            read(u), read(v);
            G[u].pb(v), G[v].pb(u);
        }
        read(f); rep(i, 1, f) read(h[i]);
        read(k); rep(i, 1, k) read(p[i]);
        vector<pii> q; q.pb({1, 0});
        dp[1][0] = 1;
        while(q.size()) {
            //防止同一层之间的点互相到达
            for(auto t : q) vis[t.fi] = 1;
            vector<pii> nex;
            for(auto t : q) {
                for(auto u : G[t.fi]) {
                    int state = t.se;
                    for(int i = 1; i <= k; i++)
                        if(u == h[p[i]]) state |= (1 << i - 1);
                    if(!dp[u][state] && !vis[u]) {
                        nex.pb({u, state});
                        dp[u][state] = 1;
                    }
                } 
            }
            q = nex;
        }
        rep(i, 1, k) h[p[i]] = 0;
        bitset<64> now, pre;
        pre[0] = 1;
        for(int i = 1; i <= f; i++) {
            if(!h[i]) continue;
            now = pre;
            int u = h[i];
            for(int x = 0; x < 64; x++)
                for(int y = 0; y < 64; y++)
                    if(dp[u][y]) now[y | x] = now[y | x] | pre[x];
            pre = now;
        }
        int ans = 0;
        for(int i = 0; i < 64; i++) 
            if(now[i]) ans = max(ans, __builtin_popcount(i));
        printf("%d\n", k - ans);    
    }

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值