复习计划-状态压缩DP

状态压缩DP
  • 观察数据范围
  • 提取题目中状态关系
  • 设计状态转移方程-
代码套路
  • 先计算出所有合法状态
  • 再根据情况处理出所有合法状态可以转移到的合法状态
经典例题 (棋盘式)
  • SGU223
//#define LOCAL
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)

template<typename T>
void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}
using namespace std;

ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a % b);
}

ll lcm(ll a, ll b) {
    return a / gcd(a, b) * b;
}

int n , m;
const int M = 2050 , N = 13;
vector <int> state, head[M];
int cnt[M];
ll dp[N][200][M];
bool check (int x)
{
    for (int i = 0 ; i < n ; i ++)
        if ( (x >> i & 1) && (x >> (i + 1) & 1) )
            return false;
    return true;
}
int count (int x)
{
    int res = 0;
    for (int i = 0 ; i < n ; i ++)
        res += (x >> i & 1);
    return res;
}
int main (void)
{
    read (n , m);
    for (int i = 0 ; i < (1 << n) ; i ++)
    {
        if (check(i))
        {
            state.pb(i);
            cnt[i] = count(i);
        }
    }
    for (int i = 0 ; i < state.size() ; i ++)
    {
        for (int j = 0 ; j < state.size() ; j ++)
        {
            int a = state[i] , b = state[j];
            if ((a & b) == 0 && check(a | b))
                head[i].pb(j);
        }
    }
    dp[0][0][0] = 1;
    for (int i = 1 ; i <= n+1 ; i ++)
        for (int j = 0 ; j <= m ; j ++)
            for (int a = 0 ; a < state.size() ; a ++)
                for (int b : head[a])
                {
                    int c = cnt[state[a]];
                    if (j >= c)
                        dp[i][j][a] += dp[i-1][j-c][b];
                }
    write(dp[n+1][m][0]),LF;
}
/*
4
1 2 2 3
0 1 3 1
1 2 3 2
 */
  • LuoGu P1879
//#define LOCAL
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)

template<typename T>
void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}
using namespace std;

ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a % b);
}

ll lcm(ll a, ll b) {
    return a / gcd(a, b) * b;
}

int n , m;
const int N = 14 , M = 1 << 14, mod = 100000000;
int ma[N][N];
vector <int> state[N];
int dp[N][M];
bool check (int x , int val)
{
    for (int i = 0 ; i < m ; i ++)
       if ( (val >> i & 1) && (val >> (i + 1) & 1) )
           return false;
   for (int i = 0 ; i < m ; i ++)
       if ( (val >> i & 1) && !ma[x][i+1] )
           return false;
   return true;
}
int main(void)
{
    read (n , m);
    for (int i = 1 ; i <= n ; i ++)
        for (int j = 1 ; j <= m ; j ++)
            read (ma[i][j]);

    state[0].pb(0);
    for (int i = 1 ; i <= n ; i ++)
        for (int j = 0 ; j < (1 << m) ; j ++)
            if (check(i , j))
                state[i].pb(j);
    dp[0][0] = 1;
    for (int i = 1 ; i <= n ; i ++)
    {
        for (int x = 0 ; x < state[i].size() ; x ++)
        {
            for (int y = 0 ; y < state[i-1].size() ; y ++)
            {
                int a = state[i][x] , b = state[i-1][y];
                if ((a & b) == 0)
                    dp[i][x] += dp[i - 1][y], dp[i][x] %= mod;
            }
        }
    }
    ll sum = 0;
    for (int i = 0 ; i < state[n].size() ; i ++)
        sum = sum + dp[n][i], sum %= mod;
    write(sum), LF;
}
/*
4
1 2 2 3
0 1 3 1
1 2 3 2
 */
  • P2704
//#define LOCAL
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)

template<typename T>
void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}
using namespace std;

ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a % b);
}

ll lcm(ll a, ll b) {
    return a / gcd(a, b) * b;
}
const int N = 105,  M = (1 << 11);
int n , m;
char ma[N][N];
vector <int> state[N];
int dp[N][M][M], cnt[M];
bool check (int x, int val)
{
    for (int i = 0 ; i < m ; i ++)
        if ((val >> i & 1) && ((val >> i + 1 & 1) || (val >> i + 2 & 1)))
            return false;
    for (int i = 0 ; i < m ; i ++)
        if ( (val >> i & 1) && ma[x][i+1] == 'H')
            return false;
    return true;
}
int count (int val)
{
    int res = 0;
    for (int i = 0 ; i < m ; i ++)
        if (val >> i & 1) res += 1;
    return res;
}
bool ok(int val1 , int val2 , int val3)
{
    for (int i = 0 ; i < m ; i ++)
    {
        if ((val1 >> i & 1) + (val2 >> i & 1) + (val3 >> i & 1) >= 2)
            return false;
    }
    return true;
}
int main(void)
{
    read (n , m);
    for (int i = 1 ; i <= n ; i ++)
        scanf("%s",ma[i] + 1);
    for (int i = 0 ; i < (1 << m) ; i ++)
        cnt[i] = count(i);

    for (int i = 1 ; i <= n ; i ++)
        for (int j = 0 ; j < 1 << m ; j ++)
            if (check(i , j))
                state[i].pb(j);
    state[0].pb(0);
    for (int i = 0 ; i < state[1].size() ; i ++)
        dp[1][i][0] = cnt[state[1][i]];

    for (int i = 2 ; i <= n ; i ++)
    {
        for (int x = 0 ; x < state[i].size() ; x ++)
        {
            for (int y = 0 ; y < state[i-1].size() ; y ++)
            {
                for (int z = 0 ; z < state[i-2].size() ; z ++)
                {
                    int a = state[i][x] , b = state[i-1][y] , c = state[i-2][z];
                    if (ok (a, b, c)) {
                        dp[i][x][y] = max(dp[i - 1][y][z] + cnt[a], dp[i][x][y]);
                    }
                }
            }
        }
    }
    int ans = 0;
    for (int i = 0 ; i < state[n].size() ; i ++)
        for (int j = 0 ; j < state[n-1].size() ; j ++)
            ans = max(ans, dp[n][i][j]);
    write(ans), LF;
}
/*
4
1 2 2 3
0 1 3 1
1 2 3 2
 */
  • P2831
//#define LOCAL
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair <int, int>
#define pdd pair <double,double>
#define pll pair <ll,ll>
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)

template<typename T>
void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}
using namespace std;

ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a % b);
}

ll lcm(ll a, ll b) {
    return a / gcd(a, b) * b;
}
const double eps = 1e-6;
const int N = 20 , M = 1 << 18;
int T;
int n , m;
pdd q[N];
int path[N][N], dp[M];
int check (double x, double y)
{
    if (fabs(x - y) < eps)
        return 0;
    return 1;
}
int main() {
    read(T);
    while (T--)
    {
        read (n , m);
        for (int i = 0 ; i < n ; i ++)
            scanf ("%lf %lf", &q[i].fi, &q[i].se);
        mem(path,0);
        for (int i = 0 ; i < n ; i ++)
        {
            path[i][i] = 1 << i;
            for (int j = 0 ; j < n ; j ++)
            {
                double x1 = q[i].fi , y1 = q[i].se;
                double x2 = q[j].fi , y2 = q[j].se;
                if (!check(x1, x2)) continue;
                double a = (y1/x1 - y2/x2) / (x1 - x2);
                double b = y1 / x1 - a * x1;
                if (a > 0 || !check(a,0.0)) continue;
                int state = 0;
                for (int k = 0 ; k < n ; k ++)
                {
                    double x = q[k].fi , y = q[k].se;
                    if (!check(a * x * x + b * x, y))
                        state += (1 << k);
                }
                path[i][j] = state;
            }
        }
        //DBG;
        mem(dp,0x3f);
        dp[0] = 0;
        for (int i = 0 ; i+1 < 1 << n ; i ++)
        {
            int x = 0;
            for (int j = 0 ; j < n ; j ++)
            {
                if (!(i >> j & 1))
                {
                    x = j;
                    break;
                }
            }
            for (int j = 0 ; j < n ; j ++)
                dp[i | path[x][j]] = min (dp[i | path[x][j]], dp[i] + 1);
        }
        cout << dp[(1 << n) - 1] << endl;
    }
}
/*
4
1 2 2 3
0 1 3 1
1 2 3 2
 */
  • P3959
//#define LOCAL
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)

template<typename T>
void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}
using namespace std;

ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a % b);
}

ll lcm(ll a, ll b) {
    return a / gcd(a, b) * b;
}

const int N = 13 , M = 1 << N;
int n , m;
int d[N][N], dp[M][N], g[M];
int main (void)
{
    read(n, m);
    mem(d, INF);
    for (int i = 0 ; i < n ; i ++)
        d[i][i] = 0;
    for (int i = 1; i <= m; i++)
    {
        int u , v, w;
        read (u , v, w);
        u -- , v --;
        d[u][v] = d[v][u] = min (d[u][v] , w);
    }

    for (int i = 1 ; i < 1 << n ; i ++)
        for (int j = 0 ; j < n ; j ++)
            if (i >> j & 1)
            {
                for (int k = 0 ; k < n ; k ++)
                {
                    if (d[j][k] != INF)
                        g[i] |= 1 << k; //以i为原集合连边后能构造出的集合
                }
            }

    mem(dp , INF);
    for (int i = 0 ; i < n ; i ++) dp[1 << i][0] = 0;
    for (int i = 1 ; i < 1 << n ; i ++)
        for (int j = i ; j ; j = (j-1) & i) //枚举i的子集
            if ((g[j] & i) == i) //子集+边构造的集合是否能够包含i
            {
                int state = i ^ j; //边指向的点
                int cost = 0;
                for (int k = 0; k < n; k++)
                    if (state >> k & 1)
                    {
                        int t = INF;
                        for (int l = 0 ; l < n ; l ++)
                            if (j >> l & 1)
                                t = min (d[k][l], t); //选出j集合中中指向state集合的边的最小值
                        cost += t;
                    }
                for (int k = 1 ; k < n ; k ++)
                    dp[i][k] = min (dp[i][k], dp[j][k-1] + cost * k);
            }

    int ans = INF;
    for (int i = 0 ; i < n ; i ++)
        ans = min (ans, dp[(1 << n) - 1][i]);
    cout << ans << endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值