zoukankan      html  css  js  c++  java
  • 状态压缩dp

    所谓的状态压缩dp其实就是使用一个整数表示一个状态然后其余的就跟普通的动态规划是一样的了。

    通常的状态有集合的表示(使用2进制表示有或没有)

    2441

    题目大意:

    有n个人可以去pi个球场,问要求一个球场只能有一个人去且满足所以人都去一个的方案数有多少种

    分析:

    dp[i][j]表示当前第i个人选择状态为j的方案数,那么转移就是

    dp[i][j]=sum{dp[i-1][s']}s'为之前的状态

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <set>
     5 #include <algorithm>
     6 #include <map>
     7 #include <queue>
     8 #include<cmath>
     9 #include<vector>
    10 #define maxn 20
    11 #define maxm 20
    12 #define mod 1000000000000000000
    13 #define INF 0x3f3f3f3f
    14 using namespace std;
    15 int a[maxn][maxn];
    16 int n,m;
    17 int dp[1<<maxm+1];
    18 int state[1<<maxm+1];
    19 int main (){
    20     while(scanf("%d%d",&n,&m)!=EOF){
    21         for(int i=1;i<=n;++i){
    22             scanf("%d",&a[i][0]);
    23             for(int j=1;j<=a[i][0];++j){
    24                 scanf("%d",&a[i][j]);
    25                 a[i][j]--;
    26             }
    27         }
    28         for(int i=0;i<(1<<m);++i){
    29             state[i] =0;
    30             for(int j=0;j<m;++j){
    31                 if(i&(1<<j))state[i]++;
    32             }
    33         }
    34         memset(dp,0,sizeof(dp));
    35         for(int i=1;i<=a[1][0];++i){
    36             dp[(1<<a[1][i])]=1;
    37         }
    38         for(int i=2;i<=n;++i){
    39             for(int j=(1<<m)-1;j>=0;--j){
    40                 if(state[j]!=i)continue;
    41                 for(int k=1;k<=a[i][0];++k){
    42                     if(!(j&(1<<a[i][k])))continue;
    43                     dp[j]+=dp[j-(1<<a[i][k])];
    44                 }
    45             }
    46         }
    47         int ans=0;
    48         for(int i=0;i<(1<<m);++i){
    49             if(state[i]==n)ans+=dp[i];
    50         }
    51         printf("%d
    ",ans);
    52     }
    53 }
    View Code

    2836

    题意:

    给你n个二维的点,要求画两边平行于x,y轴的长方形去覆盖所有的点,要求一个长方形最少覆盖两个点,问长方形面积总和最小值。

    分析:

    首先枚举长方形的两个顶点,构造n*n/2个长方形,注意如果两个点的x,y有一个相同要特殊处理。

    然后对于每一个长方形计算面积以及状态(覆盖了哪些点,用2进制表示) 

    接下来就是dp的计算了。

    dp[i][j]表示选到第i个长方形是状态为j的最小面积。转移就是分第i个选还是不选,跟01背包是一样的。

    dp[i][j]=min(dp[i-1][j],dp[i-1][j&(~r[i].state)]+r[i].s);

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <set>
     5 #include <algorithm>
     6 #include <map>
     7 #include <queue>
     8 #include<cmath>
     9 #include<vector>
    10 #define maxn 15
    11 #define maxm (15*15)/2
    12 #define mod 1000000000000000000
    13 #define INF 0x3f3f3f3f
    14 using namespace std;
    15 struct point{
    16     int x,y;
    17 }a[maxn];
    18 int n;
    19 int dp[maxm][1<<maxn+1];
    20 struct rect{
    21     int x1,y1,x2,y2;
    22     int s,state;
    23 }r[maxm];
    24 int cnt;
    25 bool in(rect a,point b){
    26     int minx = min(a.x1,a.x2);
    27     int maxx = max(a.x1,a.x2);
    28     int miny = min(a.y1,a.y2);
    29     int maxy = max(a.y1,a.y2);
    30     if(b.x>=minx&&b.x<=maxx&&b.y>=miny&&b.y<=maxy)return true;
    31     else return false;
    32 }
    33 void init(){
    34     cnt=1;
    35     for(int i=0;i<n;++i){
    36         for(int j=i+1;j<n;++j){
    37             if(i==j)continue;
    38             //if(a[i].x==a[j].x||a[i].y==a[j].y)continue;
    39             r[cnt].x1=a[i].x;r[cnt].y1=a[i].y;
    40             r[cnt].x2=a[j].x;r[cnt].y2=a[j].y;
    41             if(a[i].x==a[j].x)r[cnt].s=abs(a[i].y-a[j].y);
    42             else if(a[i].y==a[j].y)r[cnt].s = abs(a[i].x-a[j].x);
    43             else r[cnt].s = abs(a[i].x-a[j].x)*abs(a[i].y-a[j].y);
    44             cnt++;
    45         }
    46     }
    47     for(int i=1;i<cnt;++i){
    48         r[i].state=0;
    49         for(int j=0;j<n;++j){
    50             if(in(r[i],a[j]))r[i].state|=(1<<j);
    51         }
    52     }
    53 }
    54 int main (){
    55     while(scanf("%d",&n)!=EOF){
    56         if(n==0)break;
    57         for(int i=0;i<n;++i)scanf("%d%d",&a[i].x,&a[i].y);
    58         init();
    59         for(int i=0;i<cnt;++i){
    60             for(int j=0;j<(1<<n);++j)dp[i][j]=INF;
    61             dp[i][0]=0;
    62         }
    63         for(int i=1;i<cnt;++i){
    64             for(int j=0;j<(1<<n);++j){
    65                 dp[i][j]=min(dp[i-1][j],dp[i-1][j&(~r[i].state)]+r[i].s);
    66             }
    67         }
    68         int ans=dp[cnt-1][(1<<n)-1];
    69         printf("%d
    ",ans);
    70     }
    71 }
    View Code

    3411

    题目大意:

    有n个点,m个边的有向图,有重边。对于每一条边ai到bi点有两种收费方式,一种是如果到过ci点就收费pi否则收费ri,问从1到N的最短花费

    其实是个图论+dp,dp[i][j]表示当前在i点,之前走过的点的集合状态为j的最小花费。

    那么对于每个dp[i][j]去更新其他的状态,两种收费方式,类似于最短路里面的松弛过程。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <set>
     5 #include <algorithm>
     6 #include <map>
     7 #include <queue>
     8 #include<cmath>
     9 #include<vector>
    10 #define maxn 15
    11 #define maxm 15
    12 #define mod 1000000000000000000
    13 #define INF 0x3f3f3f3f
    14 using namespace std;
    15 int dp[maxn][(1<<maxn)+1];
    16 bool inq[maxn][(1<<maxn)+1];
    17 struct node{
    18     int b,c,p,r;
    19     node(){}
    20     node(int _b,int _c,int _p,int _r){
    21         b=_b;c=_c;p=_p;r=_r;
    22     }
    23 };
    24 vector<node>G[maxn];
    25 int n,m;
    26 void init(){
    27     memset(inq,false,sizeof(inq));
    28     for(int i=0;i<maxn;++i){
    29         for(int j=0;j<(1<<maxn);++j){
    30             dp[i][j]=INF;
    31         }
    32     }
    33 }
    34 void solve(){
    35     init();
    36     queue<int>q1,q2;
    37     dp[0][1]=0;
    38     inq[0][1]=true;
    39     q1.push(0),q2.push(1);
    40     while(!q1.empty()){
    41         int u = q1.front();q1.pop();
    42         int s = q2.front();q2.pop();
    43         inq[u][s]=false;
    44         for(int i=0;i<G[u].size();++i){
    45             int v = G[u][i].b,c = G[u][i].c,p = G[u][i].p,r=G[u][i].r;
    46             if(s&(1<<c)){
    47                 if(dp[u][s]+p<dp[v][s|(1<<v)]){
    48                     dp[v][s|(1<<v)]=dp[u][s]+p;
    49                     if(!inq[v][s|(1<<v)]){
    50                         q1.push(v);
    51                         q2.push(s|(1<<v));
    52                         inq[v][s|(1<<v)]=true;
    53                     }
    54                 }
    55             }
    56             else {
    57                 if(dp[u][s]+r<dp[v][s|(1<<v)]){
    58                     dp[v][s|(1<<v)]=dp[u][s]+r;
    59                     if(!inq[v][s|(1<<v)]){
    60                         q1.push(v);
    61                         q2.push(s|(1<<v));
    62                         inq[v][s|(1<<v)]=true;
    63                     }
    64                 }
    65             }
    66         }
    67     }
    68     int ans = INF;
    69     for(int i=0;i<(1<<n);++i){
    70         if((i&1)&&(i&(1<<(n-1))))ans = min(ans,dp[n-1][i]);
    71     }
    72     if(ans==INF)printf("impossible
    ");
    73     else printf("%d
    ",ans);
    74 }
    75 int main (){
    76     while(scanf("%d%d",&n,&m)!=EOF){
    77         for(int i=0;i<maxn;++i)G[i].clear();
    78         for(int i=0;i<m;++i){
    79             int a,b,c,p,r;
    80             scanf("%d%d%d%d%d",&a,&b,&c,&p,&r);
    81             a--;b--;c--;
    82             G[a].push_back(node(b,c,p,r));
    83         }
    84         solve();
    85     }
    86 }
    View Code
  • 相关阅读:
    通过串口抓取图片
    Qt也有垃圾回收(通过QScopedPointer实现),下决心在项目里使用QScopedPointer,省了太多事情了,而且更安全!!
    IOS端 margin-top 和 margin-bottom 使用负数时的区别
    使用ROME解析rss,如何获取icon图标
    SVG图片如何调整大小和颜色
    Js点击触发Css3的动画Animations、过渡Transitions效果
    如何判断是否为同一个App,Ionic3如何修改包名
    如何使用JPQL写纯SQL语句
    为何在新线程中使用注解获取不到Spring管理的Bean
    Ionic的NavController 和ModalController 的区别
  • 原文地址:https://www.cnblogs.com/shuzy/p/3826527.html
Copyright © 2011-2022 走看看