初步---状压DP

【使用情况】:

在状态比较多的情况下,同时状态只需要记录是或非,使用二进制将其压缩,从而达到缩减时间复杂度的效果。

由于要使用二进制来表示状态,所以这类问题的数据范围会相对较小\(\left ( n\leq 20左右\right )\),时间复杂度经常含有 O(2n).代替爆搜的常用方法

【二进制基础】:

若当前状态为s,对s有如下操作:(第i位是指从右往左数的第i位)

1.判断第i位是否为0:(s&(1<<(i-1)))==0

2.判断第i位是否为1:((1<<(i-1))&s)>0

3.将第i位置0:s&(~(1<<(i-1)))

4.将第i位置1:s|(1<<(i-1))

5.把一个数字二进制下最靠右的第一个1去掉:s=s&(s-1)

6.最右边 i 位:s&((1<<(i-1))-1)

7.第i位取反:s^(1<<(i-1))

8.枚举子集:

1 for(int s1=s;s1!=0;s1=(s1-1)&s){
2     s2=s^s1;
3 }

 入门题目:

吃奶酪

 

 题解:其实可以比较容易想到dp,dp部分状态转移见代码,状态情况从\(000000000000000\left ( 15位\right )\sim111111111111111\left ( 15位\right )\)\(\left ( 2进制形式\right )\),化为\(10\)进制,最大也就是\(2^{16}-1\),可以开一个二维dp数组:\(dp\left [ i\right ]\left [ j\right ]表示i状态的最后一步是j位置\)

具体见代码:

 1 #include <iostream>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 typedef long long ll;
 5 const int maxn=1e5+10;
 6 const double inf=9999999999.9;
 7 const int mod=1e9+7;
 8 #define rep(i,first,second) for(int i=first;i<=second;i++)
 9 #define dep(i,first,second) for(int i=first;i>=second;i--)
10 
11 struct point{double x,y;}p[30];
12 double dp[1<<15][20];
13 double dis[20][20];
14 int n;
15 
16 double Dis(int i,int j){
17     double xx=p[i].x-p[j].x;
18     double yy=p[i].y-p[j].y;
19     double d=sqrt((1.0*xx*xx)+(1.0*yy*yy));
20     return d;
21 }
22 
23 void dpFuc(){
24     rep(i,1,(1<<n)-2){//计算从第i种状态可以到达的所有状态
25         for(int pre=0;pre<n;pre++){//最后一步,从第pre位
26             if( !(i&(1<<pre))) continue;//跳过还没走过的位置
27             for(int now=0;now<n;now++){//到now位
28                 if((i&(1<<now))) continue;//跳过已经走过的位置
29                 dp[i|(1<<now)][now]=min(dp[i|(1<<now)][now],dp[i][pre]+dis[now+1][pre+1]);
30             }
31         }
32     }
33 }
34 
35 int main()
36 {
37     ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
38     memset(dp,127,sizeof(dp));//double 型赋最大值
39 
40     cin>>n;
41     p[0].x=0.00,p[0].y=0.00;
42     rep(i,1,n) cin>>p[i].x>>p[i].y;
43     rep(i,0,n){//用(0,0)到其余各点的距离初始化dp数组
44         rep(j,i+1,n){
45             double dist=Dis(i,j);
46             dis[i][j]=dist;dis[j][i]=dist;
47         }
48     }
49     rep(i,0,n-1){
50         dp[1<<i][i]=dis[0][i+1];
51     }
52 
53     dpFuc();
54     double ans=inf;
55     rep(i,0,n-1){
56         ans=min(ans,dp[(1<<n)-1][i]);
57     }
58     cout<<fixed<<setprecision(2)<<ans<<endl;
59     return 0;
60 }

注意:

 1 #include <iostream>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 typedef long long ll;
 5 const int maxn=1e5+10;
 6 const double inf=9999999999.9;
 7 const int mod=1e9+7;
 8 #define rep(i,first,second) for(int i=first;i<=second;i++)
 9 #define dep(i,first,second) for(int i=first;i>=second;i--)
10 
11 struct point{double x,y;}p[30];
12 double dp[1<<15][20];
13 double dis[20][20];
14 int n;
15 
16 double Dis(int i,int j){
17     int xx=p[i].x-p[j].x;//这里错了,一定要定义成double
18     int yy=p[i].y-p[j].y;//这里错了,一定要定义成double 
19     double d=sqrt((1.0*xx*xx)+(1.0*yy*yy));
20     return d;
21 }
22 
23 void dpFuc(){
24     rep(i,1,(1<<n)-2){
25         for(int pre=0;pre<n;pre++){
26             if( !(i&(1<<pre))) continue;
27             for(int now=0;now<n;now++){
28                 if((i&(1<<now))) continue; 
29                 dp[i|(1<<now)][now]=min(dp[i|(1<<now)][now],dp[i][pre]+dis[now+1][pre+1]);
30             }
31         }
32     }
33 }
34 
35 int main()
36 {
37     ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
38     memset(dp,127,sizeof(dp));//double 型赋最大值
39 
40     cin>>n;
41     p[0].x=0.00,p[0].y=0.00;
42     rep(i,1,n) cin>>p[i].x>>p[i].y;
43     rep(i,0,n){//用(0,0)到其余各点的距离初始化dp数组
44         rep(j,i+1,n){
45             double dist=Dis(i,j);
46             dis[i][j]=dist;dis[j][i]=dist;
47         }
48     }
49     rep(i,0,n-1){
50         dp[1<<i][i]=dis[0][i+1];
51     }
52 
53     dpFuc();
54     double ans=inf;
55     rep(i,0,n-1){
56         ans=min(ans,dp[(1<<n)-1][i]);
57     }
58     cout<<fixed<<setprecision(2)<<ans<<endl;
59     return 0;
60 }
WA

 

posted @ 2020-05-07 01:06  swsyya  阅读(211)  评论(0)    收藏  举报

回到顶部