lightoj 1018 dp

题目链接:http://lightoj.com/volume_showproblem.php?problem=1018

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

const int maxe = 50000;
const int maxn = 16;
const int INF  = 0x3f3f3f;
int X[maxn],Y[maxn];
int S[maxn][maxn];
int T,N;
int dp[1<<maxn];
int a[1<<maxn];

int Cross(int x1,int y1,int x2,int y2){
     return x1*y2 - y1 * x2;
}
void init(){
    for(int i=0;i<maxn;i++) a[1<<i]=i;
}
int dfs(int x){   //求点集S。
    if(dp[x]!=-1) return dp[x];
    int i=a[x&-x];   //点集S的最低位上的点。
    dp[x]=INF;
    for(int k=x-(x&-x);k;k-=k&-k){ //S-(S&-S)是去除i后的点集。
        int j=a[k&(-k)];
        dp[x]=min(dp[x],dfs(x^(S[i][j]&x))+1);
    }
    return dp[x];
}
int main()
{
    //freopen("E:\acm\input.txt","r",stdin);

    init();
    cin>>T;
    for(int cas=1;cas<=T;cas++){
        scanf("%d",&N);
        for(int i=0;i<N;i++)  scanf("%d %d",&X[i],&Y[i]);

        memset(S,0,sizeof(S));
        for(int i=0;i<N;i++)
            for(int j=i+1;j<N;j++){
                for(int k=0;k<N;k++){
                    if(!Cross(X[j]-X[i],Y[j]-Y[i],X[k]-X[i],Y[k]-Y[i]))
                        S[i][j] |= (1<<k);   //i,j所在直线上其他点的集合。
                }
                S[j][i] = S[i][j];
            }
       int ALL = (1<<N)-1;
       memset(dp,-1,sizeof(dp));
       dp[0] = 0;
       for(int i=0;i<N;i++)  dp[1<<i] = 1;
       printf("Case %d: %d
",cas,dfs(ALL));
    }
}
View Code
原文地址:https://www.cnblogs.com/acmdeweilai/p/3283385.html