zoukankan      html  css  js  c++  java
  • cf298F:状压dp+剪枝

    div2的F题,只想到了一个复杂度略高的dp,T了几次,后来加了剪枝减掉一些无用的状态终于过了。。 

    题意:

    一个n*m的矩阵 (n<=5,m<=20),对格子进行黑白染色,已经给出了每行每列黑色联通块的个数,要求输出一组答案,满足有解。

    思路:

    首先发现n只有5,考虑按列处理,每列总共有2^5=32种状态;又发现对于给出的联通块个数,最坏情况是当联通块个数等于1或者2的时候有15种情况

    比直接二进制处理快了一倍。所以我们可以预先处理出联通块个数为0~3时对于的二进制状态;

    找到了列的基本状态,现在来考虑转移:

    首先在转移时应该满足每行的黑色联通块个数,所以每行当前的联通块个数是需要保存的,由于m<=20所以每行最多有0~10这11种情况,考虑到5行就总共有11^5种状态

    所以总共的状态数即为 20*15*11^5=48315300 由于cf的机器很强大这个状态数基本算是可以接受了

    转移时处理如下:对于每一行如果上一列为0且当前列为1,则联通块数目+1,其他情况联通块数目不变。

    这样我们就可以解决整个dp的过程了,由于题目要求输出染色方案,我们就需要记录每一个状态的前驱,最后通过前驱获得答案

    但是直接交上去还是会T的,这里有两个剪枝可以使用

    1.在转移过程中如果当前行的联通块个数已经大于题目给的个数,直接把这个状态减掉

    2.在转移过程中如果当前行的联通块个数在剩下的列里怎么取(最好情况为一黑一白这样染)都不可能达到题目给的个数,把这个状态减掉

    最后终于ac了!

    代码:

      1 #include <iostream>
      2 #include <stdio.h>
      3 #include<string.h>
      4 #include<algorithm>
      5 #include<string>
      6 #include<ctype.h>
      7 #include<vector>
      8 using namespace std;
      9 #define MAXN 10000
     10 bool dp[20][16][161060];
     11 int pret[49000000];
     12 int x[6];
     13 int y[21];
     14 int p[7];
     15 int ans[21];
     16 int  v[21][21];
     17 int nn[21];
     18 int n,m;
     19 int fun(int s)
     20 {
     21     int res=0;
     22     int pre=0;
     23     for(int i=0; i<n; i++)
     24     {
     25         if((s&(1<<i))&&pre==0)
     26         {
     27             res++;
     28         }
     29         pre=(bool)(s&(1<<i));
     30     }
     31     return  res;
     32 }
     33 inline int get(int s,int i)
     34 {
     35     return (s%p[i+1])/p[i];
     36 }
     37 int fuck(int s,int pre,int now,int pos)
     38 {
     39     int res=0;
     40     for(int i=0; i<n; i++)
     41     {
     42         int tmp=(get(s,i)+((!(pre&(1<<i)))&&(now&(1<<i))));
     43         if(tmp>x[i])
     44             return -1;
     45         if(tmp+(m-pos)/2<x[i])
     46             return -1;
     47         res+=tmp*p[i];
     48     }
     49     return res;
     50 }
     51 inline int make(int i,int j,int s)
     52 {
     53     return s+j*161051+i*15*161051;
     54 }
     55 
     56 inline int getj(int t)
     57 {
     58     return (t%(15*161051))/161051;
     59 }
     60 
     61 char s[30][30];
     62 int main()
     63 {
     64     cin>>n>>m;
     65     p[0]=1;
     66     for(int i=1; i<=6; i++)
     67     {
     68         p[i]=p[i-1]*11;
     69     }
     70     for(int i=0; i<(1<<n); i++)
     71     {
     72         int tmp=fun(i);
     73         v[tmp][nn[tmp]++]=i;
     74     }
     75     for(int i=0; i<n; i++)
     76     {
     77         cin>>x[i];
     78     }
     79     for(int i=0; i<m; i++)
     80     {
     81         cin>>y[i];
     82     }
     83     for(int i=0; i<nn[y[0]]; i++)
     84     {
     85         dp[0][i][fuck(0,0,v[y[0]][i],0)]=1;
     86     }
     87     int now,pre,st;
     88     for(int i=1; i<m; i++)
     89     {
     90         for(int j=0; j<nn[y[i-1]]; j++)
     91         {
     92             for(int s=0; s<161051; s++)
     93             {
     94                 if(dp[i-1][j][s])
     95                 {
     96                     for(int k=0; k<nn[y[i]]; k++)
     97                     {
     98                         st=fuck(s,v[y[i-1]][j],v[y[i]][k],i);
     99                         if(st<0)
    100                             continue;
    101                         dp[i][k][st]=1;
    102                         pret[make(i,k,st)]=make(i-1,j,s);
    103                     }
    104                 }
    105             }
    106         }
    107     }
    108     now=0;
    109     for(int i=0;i<n;i++)
    110     {
    111         now+=x[i]*p[i];
    112     }
    113     int j=-1;
    114     for(int i=0;i<nn[y[m-1]];i++)
    115     {
    116         if(dp[m-1][i][now])
    117         {
    118             j=i;
    119             break;
    120         }
    121     }
    122 
    123     now=make(m-1,j,now);
    124     for(int i=m-1;i>=0;i--)
    125     {
    126         ans[i]=v[y[i]][getj(now)];
    127         now=pret[now];
    128     }
    129     for(int i=0;i<n;i++)
    130     {
    131         for(int j=0;j<m;j++)
    132         {
    133             s[i][j]=((ans[j])&(1<<i))?'*':'.';
    134         }
    135     }
    136     for(int i=0;i<n;i++)
    137     {
    138         puts(s[i]);
    139     }
    140     return 0;
    141 }
    View Code
  • 相关阅读:
    C#基元类型、引用类型和值类型
    UML类图中泛化、实现、依赖、关联、聚合、组合关系
    简述:聚集索引和非聚集索引的区别
    面向对象编程的三特性、七原则和六视点
    设计模式学习笔记——解释器模式(Interpreter)
    设计模式学习笔记——组合模式(Composite)
    程序员编程利器:20款最好的免费的IDEs和编辑器
    奇技淫巧之浏览器秒秒钟变编辑器
    前端技术Jquery与Ajax使用总结
    Chrome也疯狂之Vimium插件
  • 原文地址:https://www.cnblogs.com/oneshot/p/4452944.html
Copyright © 2011-2022 走看看