状态压缩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\n",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\n",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\n");
73     else printf("%d\n",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

 

posted @ 2014-07-05 22:40  默默如潮  阅读(658)  评论(0)    收藏  举报