状压dp专题----2017.10.1

    • 前言没有前言
  • T1 Hie with the Pie
    • 题意
    • 解析
      • 代码
    • 提示
    • 出处
  • T2 Doing Homework
    • 题意
    • 解析
      • 代码
    • 提示
    • 出处
  • T3 Card Collector
    • 题意
    • 解析
      • 代码
    • 提示
    • 出处

前言:没有前言.

T1 Hie with the Pie

题意:

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

解析:

最短路+状压.

代码:

#include 
#include 
#include 
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 
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 
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;
}

提示:

非常迷的计算方法.

出处:

点这里

你可能感兴趣的:(总结)