我是靠谱客的博主 冷酷故事,最近开发中收集的这篇文章主要介绍LOJ2540. 「PKUWC2018」随机算法【概率期望DP+状压DP】,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

LINK


思路

首先在加入几个点之后所有的点都只有三种状态

一个是在独立集中,一个是和独立集联通,还有一个是没有被访问过

然后前两个状态是可以压缩起来的

因为我们只需要记录下当前独立集大小和是否被访问过,然后每次加点我们直接枚举加入独立集中的点然后周围联通的点都可以一起访问,只要保证当前枚举的点没有被访问过就可以了

因为这样选出来的当前的点一定是不是独立集中的且不和独立集联通的

然后每次因为加入了很多个点,我们设(w_i)表示和i联通(包括i)的所有点的集合

然后就可以用排列数算了,只需要保证当前选出来的加入独立集的点在所有其他点之前算就可以了

所以是(dp_{i+1,s|w_{j}}+=dp_{i,s}*P_{n-cnt[s]-1}^{cnt[w_joplus(w_j&s)]-1})


#include<bits/stdc++.h>

using namespace std;

const int Mod = 998244353;
const int N = 21;

int n, m, w[N];
int fac[N], inv[N], cnt[1 << N];
int dp[N][1 << N];

int main() {
#ifdef dream_maker
  freopen("input.txt", "r", stdin);
#endif
  function<int(int a, int b)> add = [&](int a, int b) {
    return (a += b) >= Mod ? a - Mod : a;
  };
  
  function<int(int a, int b)> sub = [&](int a, int b) {
    return (a -= b) < 0 ? a + Mod : a;
  };
  
  function<int(int a, int b)> mul = [&](int a, int b) {
    return (long long) a * b % Mod;
  };
  
  function<int(int a, int b)> fast_pow = [&](int a, int b) {
    int res = 1;
    for (; b; b >>= 1, a = mul(a, a))
      if (b & 1) res = mul(res, a);
    return res;
  };
  
  function<int(int a, int b)> P = [&](int a, int b) {
    return (a < b) ? 0 : mul(fac[a], inv[a - b]);
  };
  
  scanf("%d %d", &n, &m);
  int up = (1 << n) - 1;
  for (int i = 1; i <= n; i++) w[i] = 1 << (i - 1);
  for (int i = 1; i <= m; i++) {
    int u, v; scanf("%d %d", &u, &v);
    w[u] |= 1 << (v - 1);
    w[v] |= 1 << (u - 1);
  }
  inv[0] = fac[0] = 1;
  for (int i = 1; i <= n; i++) fac[i] = mul(fac[i - 1], i);
  inv[n] = fast_pow(fac[n], Mod - 2);
  for (int i = n - 1; i >= 1; i--) inv[i] = mul(inv[i + 1], i + 1);
  for (int i = 1; i <= up; i++) {
    for (int j = 1; j <= n; j++) {
      cnt[i] += (i >> (j - 1)) & 1;
    }
  }
  dp[0][0] = 1;
  for (int i = 1; i <= n; i++) {
    for (int s = 0; s <= up; s++) if (dp[i - 1][s]) {
      for (int j = 1; j <= n; j++) if (!((s >> (j - 1)) & 1)) {
        dp[i][s | w[j]] = add(dp[i][s | w[j]], mul(dp[i - 1][s], P(n - cnt[s] - 1, cnt[w[j] ^ (w[j] & s)] - 1))); 
      }
    }
  }
  for (int i = n; i >= 1; i--) if (dp[i][up]) {
    printf("%d", mul(dp[i][up], inv[n]));
    break;
  }
  return 0;
} 

转载于:https://www.cnblogs.com/dream-maker-yk/p/10110401.html

最后

以上就是冷酷故事为你收集整理的LOJ2540. 「PKUWC2018」随机算法【概率期望DP+状压DP】的全部内容,希望文章能够帮你解决LOJ2540. 「PKUWC2018」随机算法【概率期望DP+状压DP】所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部