zoukankan      html  css  js  c++  java
  • [UVA11825]Hackers' Crackdown(状压dp)

    [UVA11825]Hackers' Crackdown(状压dp)

    题目传送门 洛谷

    果然水题做多了连半道难点的都能给咱干蒙...

    水题做多了降智  --鲁迅


    题目大意:见传送门

    心路历程见末尾

    正解(大概):

    状压

    虽然有些难以理解,但是这道题里面有两种集合

    一种是第i台电脑所联通的合起来就是S[i](代码内的line[i])

    另一种是指已经用了哪几台电脑

    思路开始

    反正无论如何一定得用几个S[i]拼成一个全集(1<<n)-1

    于是就有了

     1 struct Union
     2 {
     3     int A;
     4 }U[1<<16];//可以凑出来一个全集的几个电脑的集合
     5 int Uarr;
     6 void getU(int st,int A,int p)
     7 {
     8     if(st==((1<<n)-1))//这几个电脑的line集合拼成了全集
     9     {
    10         U[Uarr].A=A;
    11         Uarr++;
    12         return;
    13     }
    14     if(p>=n) return;
    15     getU(st|line[p],A|(1<<p),p+1);//集合里加这个电脑
    16     getU(st,A,p+1);//不加
    17 }
    好孩子不要急着就看哦(大雾)

    (写法比较朴素的说)

    好了我们的重点部分已经完事了

    (啥你这就完事了?)

    确实想到这个就好写了...

    如果你做过[NOIP2016]愤怒的小鸟

    那这题就更好想到了

    好了上代码

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using std::sort;
     5 int max(int a,int b){return a>b?a:b;}
     6 int n,m;
     7 
     8 int dp[1<<16];
     9 int line[16];
    10 
    11 struct sta
    12 {
    13     int s,sc;
    14 }s[1<<16];
    15 int sarr;
    16 void getsta(int st,int sc,int p)
    17 {
    18     if(p>=n)
    19     {
    20         s[sarr].s=st;
    21         s[sarr].sc=sc;
    22         sarr++;
    23         return;
    24     }
    25     getsta(st|(1<<p),sc+1,p+1);
    26     getsta(st,sc,p+1);
    27 }
    28 
    29 struct Union
    30 {
    31     int A;
    32 }U[1<<16];
    33 int Uarr;
    34 void getU(int st,int A,int p)
    35 {
    36     if(st==((1<<n)-1))
    37     {
    38         U[Uarr].A=A;
    39         Uarr++;
    40         return;
    41     }
    42     if(p>=n) return;
    43     getU(st|line[p],A|(1<<p),p+1);
    44     getU(st,A,p+1);
    45 }
    46 
    47 bool cmp(sta a,sta b)//状态按照1的数量排序(咱就好这一手) 
    48 {
    49     if(a.sc==b.sc) return a.s<b.s;
    50     else return a.sc<b.sc;
    51 }
    52 
    53 void memclr()
    54 {
    55     memset(line,0,sizeof(line));
    56     memset(dp,0,sizeof(dp));
    57     Uarr=0;
    58     sarr=0;
    59 }
    60 int main()
    61 {
    62 int xin,kk=0;
    63 while(scanf("%d",&n)!=EOF)
    64 {
    65     if(n==0) return 0;
    66     memclr();
    67     getsta(0,0,0);
    68     sort(s,s+sarr,cmp);
    69     for(int i=0;i<n;i++)
    70     {
    71         scanf("%d",&m);
    72         line[i]|=(1<<i);
    73         for(int j=1;j<=m;j++)
    74         {
    75             scanf("%d",&xin);
    76             line[i]|=(1<<xin);
    77         }
    78     }
    79     getU(0,0,0);
    80     for(int si=0;si<sarr;si++)
    81     {
    82         for(int Ui=0;Ui<Uarr;Ui++)
    83         {
    84             if((s[si].s&U[Ui].A)==U[Ui].A)
    85             {
    86                 dp[s[si].s]=max(dp[s[si].s],dp[s[si].s^U[Ui].A]+1);
    87             }
    88         }
    89     }
    90     printf("Case %d: %d
    ",++kk,dp[(1<<n)-1]);
    91 }
    92     return 0;
    93 }
    好孩子要自己思考~

    看上去做的十分轻松

    实际上

    心路历程如下:

    一开始:emmmm外层电脑使用状态里面枚举下一个使用每个电脑然后dp里存v和状态...

    写完:???

    等下等下从下面能继承过来一堆状态啊啊啊

    变成(2^n)^k了啊啊啊啊啊

    心态爆炸

    Ah~(油库里音)

    切题后:

    啥?子集的子集是3^n?

    完了我菜死了

    陷入沉思...

    3^n*n似乎也会T死

    这至少证明了我原先的思路似乎没啥可行性而不是半途而废(什么逻辑)

    心态平衡了

    Ah~(油库里音)


    以上

    本题完结

    记住

    水题做多了降智

    我没说过这句话 --鲁迅

  • 相关阅读:
    2020 7 13 每日随笔
    2020 7 10 每日总结
    2020 7 14 每日总结
    2020 7 16 每日总结
    2020 7 15 每日总结
    2020 7 19 每日总结
    2020 7 18 每日总结
    2020 7 17 每日总结
    2020 7 11
    2020 7 12
  • 原文地址:https://www.cnblogs.com/rikurika/p/10252273.html
Copyright © 2011-2022 走看看