状压dp专题----2017.10.1

本文是一篇关于状压动态规划的专题,详细解析了三道不同的问题:1) 求遍历所有点的最小价值,利用最短路+状压解决;2) 找出在最小超时时的作业顺序问题,使用状压dp模板;3) 计算收集所有卡片所需最少包数,通过巧妙的状压方法求解。每道题都提供了题意、解析、代码提示和出处链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:没有前言.

T1 Hie with the Pie

题意:

给你几个点,每个点都有到其他点的价值,请问遍历所有点的最小价值.

解析:

最短路+状压.

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int lu[20][20], dp1[20][20], dp2[1 << 11][20];
int main()
{
    int n, i, j, k;
    while (~scanf("%d", &n), n)
    {
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= n; j++)
            {
                scanf("%d", &lu[i][j]);
                dp1[i][j] = lu[i][j];
            }
        for (int j = 0; j <= n; j++)
            for (int i = 0; i <= n; i++)
                for (int k = 0; k <= n; k++)
                    dp1[i][j] = min(dp1[i][k] + lu[k][j], dp1[i][j]);
        memset(dp2, -1, sizeof(dp2));
        dp2[1][0] = 0;
        for (int i = 1; i < 1 << (n + 1); i++)
        {
            i = i | 1;
            for (int j = 0; j <= n; j++)
                if (dp2[i][j] != -1)
                    for (int k = 0; k <= n; k++)
                        if (j != k && (dp2[(1 << k) | i][k] == -1 || dp2[(1 << k) | i][k] > dp2[i][j] + dp1[j][k]))
                            dp2[(1 << k) | i][k] = dp2[i][j] + dp1[j][k];
        }
        printf("%d\n", dp2[(1 << (n + 1)) - 1][0]);
    }
    return 0;
}

提示:

可以预处理出路径的价值.

出处:

点这里

T2 Doing Homework

题意:

给你几门科目,给定必须做完的时间和做好需要的时间.,问最小超时时的做作业顺序.(字典序).

解析:

标准的状压dp模板.

代码:

#include <bits/stdc++.h>
using namespace std;
const int inf = 1 << 30;
struct node
{
    string name;
    int shi, jie;
} a[50];
struct kode
{
    int time, score, pre, now;
} dp[1 << 15];

int main()
{
    int t, i, j, s, n, end;
    cin >> t;
    while (t--)
    {
        memset(dp, 0, sizeof(dp));
        cin >> n;
        for (i = 0; i < n; i++)
            cin >> a[i].name >> a[i].shi >> a[i].jie;
        end = 1 << n;
        for (s = 1; s < end; s++)
        {
            dp[s].score = inf;
            for (i = n - 1; i >= 0; i--)
            {
                int pp = 1 << i;
                if (s & pp)
                {
                    int past = s - pp;
                    int st = dp[past].time + a[i].jie - a[i].shi;
                    if (st < 0)
                        st = 0;
                    if (st + dp[past].score < dp[s].score)
                    {
                        dp[s].score = st + dp[past].score;
                        dp[s].now = i;
                        dp[s].pre = past;
                        dp[s].time = dp[past].time + a[i].jie;
                    }
                }
            }
        }
        stack<int> S;
        int pp = end - 1;
        cout << dp[pp].score << endl;
        while (pp)
        {
            S.push(dp[pp].now);
            pp = dp[pp].pre;
        }
        while (!S.empty())
        {
            cout << a[S.top()].name << endl;
            S.pop();
        }
    }
    return 0;
}

提示:

可以把每个状态变成二进制来表示.

出处:

点这里

T3 Card Collector

题意:

给你几个卡片出现的概率,问收集所有卡的最小需要包数.

解析:

用状压表示状态.

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 21;
double nn[maxn];
double dp[1 << maxn];
int main()
{
    int n;
    while (scanf("%d", &n) != EOF)
    {
        double zz = 0;

        for (int i = 0; i < n; i++)
        {
            scanf("%lf", &nn[i]);
            zz += nn[i];
        }

        dp[(1 << n) - 1] = 0;
        zz = 1 - zz;

        for (int i = (1 << n) - 2; i >= 0; i--)
        {
            double x = 0, mm = 1;

            for (int j = 0; j < n; j++)
            {
                if ((i & (1 << j)))
                    x += nn[j];
                else
                    mm += nn[j] * dp[i | (1 << j)];
            }

            dp[i] = mm / (1 - zz - x);
        }
        printf("%.5lf\n", dp[0]);
    }
    return 0;
}

提示:

非常迷的计算方法.

出处:

点这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值