首页 > 其他 > 详细

[LightOJ1018] Brush(IV)

时间:2020-12-13 12:01:00      阅读:41      评论:0      收藏:0      [点我收藏+]

题目

最少用多少条直线可以覆盖N个点?(N<=16)

 

题解

一道水题浪费我好久时间,总是有地方写错。。。

N^3枚举两点之间的连线覆盖了多少点,然后状压dp加记忆化搜索。

注意枚举到一个未被覆盖的点就可以跳出了,顺序对答案没有影响,因为之后也一定会覆盖他。

 

代码

技术分享图片
#include<bits/stdc++.h>

using namespace std;

const int MAXN=20;
const int MAXM=(1<<18)+5;

int N,T;
int line[MAXN][MAXN];
int x[MAXN],y[MAXN];
int dp[MAXM];

int dfs(int mask){
    if(dp[mask]!=N+1) return dp[mask];
    if(__builtin_popcount(mask) <= 2) return dp[mask]=1;
    int ans=N+1;
    for(int i=1;i<=N;i++)if((1<<(i-1))&mask){
        for(int j=i+1;j<=N;j++)if((1<<(j-1))&mask){ 
            ans=min(ans,1+dfs(mask^(line[i][j]&mask)));
        }
        break;
    }
    return dp[mask]=ans;
}

int main(){
    scanf("%d",&T);
    for(int kase=1;kase<=T;kase++){
        scanf("%d",&N);
        for(int i=1;i<=N;i++){
            scanf("%d%d",&x[i],&y[i]);
        }
        if(N==1){
            printf("Case %d: 1\n",kase);
            continue;
        }
        for(int i=1;i<=N;i++){
            for(int j=i+1;j<=N;j++){
                line[i][j]=0;
                for(int k=1;k<=N;k++){
                    if((x[k]-x[i])*(y[j]-y[i])==(x[j]-x[i])*(y[k]-y[i])) line[i][j]|=1<<(k-1);
                }
            }
        }
        for(int i=1;i<(1<<N);i++) dp[i]=N+1;
        dp[0]=0;
        for(int i=1;i<=N;i++){
            for(int j=i+1;j<=N;j++){
                dp[line[i][j]]=1;
            }
        }
        printf("Case %d: %d\n",kase,dfs((1<<N)-1));
    }
    return 0;
} 
View Code

 

[LightOJ1018] Brush(IV)

原文:https://www.cnblogs.com/EDawnpractice/p/14128103.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!