Codeforces Round #454 (Div. 2) E. Party 状压dp,思维

 Codeforces Round #454 (Div. 2, based on Technocup 2018 Elimination Round 4)

E. Party

题意: n 个点,m 条边,操作:选择一个点,把它直接相邻的点相互连通。问最少要多少次操作可把这个图变成完全图。

tags: n 很小, 状压dp

dp[i] 表示要到达状态 i 的最少操作次数。

0 -> (1<<n)-1 个状态,每次用每个点去更新,如果状态 i 通过第 u 个点操作后到达了状态 j, 则 dp[j] = min(dp[j], dp[i]+1) 。

具体的操作就是状压,第 u 个点的操作也是先把它直接相邻的点用一个数存起来。

初始化:要把原本能够到达的状态初始化为 0。

复杂度O(n^2)

// 454E
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 5000005;

int n, m, dp[N], f[25], pre[N], prei[N];
int main()
{
    scanf("%d%d", &n, &m);
    rep(i,1,n) f[i] = 1<<(i-1);
    int u, v;
    rep(i,1,m)
    {
        scanf("%d%d", &u, &v);
        f[u] |= (1<<(v-1));
        f[v] |= (1<<(u-1));
    }
    mes(dp, INF);
    int tmp;
    rep(ca, 1, (1<<n)-1)   // 初始化
    {
        tmp = ca;
        rep(i,1,n)
            if( ca>>(i-1)&1 )
                tmp &= f[i];
        if(tmp == ca)   // 如果用所有点与操作后状态不变,那就说明原本就可到达
            dp[ca]=0, pre[ca]=-1;
    }
    rep(ca, 1, (1<<n)-1)   // 状态转移
    {
        rep(i,1,n)
            if( (ca>>(i-1))&1 && dp[ca]+1<dp[ca|f[i]])
            {
                dp[ca|f[i]] = dp[ca]+1;
                pre[ca|f[i]] = ca;
                prei[ca|f[i]] = i;
            }
    }
    printf("%d
", dp[(1<<n)-1]);
    for(int t=(1<<n)-1; pre[t]!=-1; t=pre[t])
        printf("%d ", prei[t]);

    return 0;
}
原文地址:https://www.cnblogs.com/sbfhy/p/8136746.html