lightoj1018(状态压缩dp)

今天写了一个多小时,才把状压dp写好。(还是在DY的指导下完成的)
但是,却也总结了一些知识:
1.对于以前的0~n-1和1~n的差别不清楚,原来只不过是最后一位的使用,但内存差距较大。
2.对于位运算的理解,又提升了一个层次,还是不错的。
3.对与状压dp的基础理解又加深了。
4.对于状压的预处理也是利用2进制来表示
5.状压dp也可以用dfs来进行解决

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define ak(aa) memset(aa,0,sizeof(aa))
#define For(aa,bb,cc) for(int aa=bb;aa<=cc;++aa)
using namespace std;
const int maxn=1<<18,inf=0x3f3f3f3f;
int dp[maxn];
int line[20][20];
int n;
struct node{
    int x,y;
}a[20];
/*
dp[]中用0表示已经被抹除,1表示还未被抹除
line[i][j]用1表示这个点在i,j之间的连线上,0表示不在
*/

void prepare(){
    For(i,1,n){
        For(j,i+1,n){
            int lx=a[i].x-a[j].x,ly=a[i].y-a[j].y;
            line[i][j]=(1<<i)|(1<<j);
            For(k,j+1,n){
                int mx=a[i].x-a[k].x,my=a[i].y-a[k].y;
                if(lx*my==mx*ly){
                    line[i][j]|=(1<<k);
                }
            }
            line[j][i]=line[i][j];
        }
    }
    return ;
}

int dfs(int now){
    if(dp[now]<inf) return dp[now];
    int num=__builtin_popcount(now);//查找1 的个数
    if(num<=2) return 1;
    int i=1;
    while(!(now&(1<<i))) ++i;//找到第一个存在的点
    For(j,i+1,n){//进行枚举点
        if(now&(1<<j))  
            dp[now]=min(dp[now],dfs(now&(~line[i][j]))+1);
    }
    return dp[now];
}

void work(int now){
    memset(dp,inf,sizeof(dp));
    dp[0]=0;//初值
    scanf("%d",&n);
    For(i,1,n){
        scanf("%d%d",&a[i].x,&a[i].y);
    }
    prepare();
    printf("Case %d: ",now);
    printf("%d\n",dfs((1<<n+1)-2));//全集要设定好
    return ;
}

int main(){
    int _;
    scanf("%d",&_);
    For(i,1,_) work(i);
    return 0;
}
发布了51 篇原创文章 · 获赞 6 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_35776579/article/details/54382136