zoukankan      html  css  js  c++  java
  • UVa 11825 (状压DP) Hackers' Crackdown

    这是我做状压DP的第一道题,状压里面都是用位运算来完成的,只要耐下心来弄明白每次位运算的含义,还是容易理解的。

    题意:

    有编号为0~n-1的n台服务器,每台都运行着n中服务,每台服务器还和若干台其他服务器相连。对于每台服务器,你可以选择停止该台以及与这台服务器相连的服务器的一项服务。如果一台服务器的所有服务都被停止,则这台服务器瘫痪。问最多能使多少台服务器瘫痪

    转化为数学模型(题目是如何抽象成这种数学模型的也要好好想想):

    把n个集合尽可能多的分成若干组,使得每组所有集合的并集为全集。这里集合Pi表示服务器i以及与其相邻服务器的集合

    算法:

    数组P[i]表示服务器i以及与其相邻服务器的集合的二进制表示

    枚举所有集合可能的组合情况,一共有2n种,计算其并集保存在cover中

    f[S]表示子集S最多可以分成多少组

    状态转移方程

    枚举S的子集S0

    f[S] = max{f[S], f[S - S0] + 1 | 这里S0是S子集而且cover[S0]为全集}

    这里再说一下枚举S0用代码实现的技巧:

    在二进制中S0的1的个数肯定比S要少,所以从数值大小上来看S0 < S

    我们先令S0 = S - 1

    那么 S & (S0 - 1)就是S的子集了

    因为上面的表达式满足两个条件:

    1. S0 < S
    2. S0的1的个数比S要少

    S ^ S0的含义

    S ^ S0代表以S为全集S0的补集,为什么用异或运算实现呢?自己动手模拟一下就清楚了,嘿嘿

    好了,写到这里,这道题就分析的很透彻了。看来位运算还是蛮有意思的

     1 //#define LOCAL
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 const int maxn = (1 << 16) + 10;
     9 int cover[maxn], p[20], f[maxn];
    10 
    11 int main(void)
    12 {
    13     #ifdef LOCAL
    14         freopen("11825in.txt", "r", stdin);
    15     #endif
    16 
    17     int n, kase = 0;
    18     while(scanf("%d", &n) == 1 && n)
    19     {
    20         memset(f, 0, sizeof(f));
    21         for(int i = 0; i < n; ++i)
    22         {
    23             int m, x;
    24             scanf("%d", &m);
    25             p[i] = (1 << i);
    26             while(m--)
    27             {
    28                 scanf("%d", &x);
    29                 p[i] |= (1 << x);
    30             }
    31         }
    32 
    33         for(int i = 0; i < (1 << n); ++i)
    34         {
    35             cover[i] = 0;
    36             for(int j = 0; j < n; ++j)
    37             {
    38                 if(i & (1 << j))
    39                     cover[i] |= p[j];
    40             }
    41         }
    42 
    43         f[0] = 0;
    44         int all = (1 << n) - 1;
    45         for(int s = 1; s < (1 << n); ++s)
    46         {
    47             f[s] = 0;
    48             for(int s0 = s; s0; s0 = (s0 - 1) & s)
    49                 if(cover[s0] == all)
    50                     f[s] = max(f[s], f[s0 ^ s] + 1);
    51         }
    52 
    53         printf("Case %d: %d
    ", ++kase, f[all]);
    54     }
    55     return 0;
    56 }
    代码君
  • 相关阅读:
    高德地图SDK大致使用
    AFNetworking 使用
    蓝牙相关
    svn 常用命令
    通过AutoLayout显示三个等宽视图
    适配相关 --AutoLayout ---SizeClass
    常用网页
    UIViewController加载过程
    UIApplication相关
    实现消息转发功能(调用非自己类方法)
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/3910723.html
Copyright © 2011-2022 走看看