最少用多少条直线可以覆盖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; }
原文:https://www.cnblogs.com/EDawnpractice/p/14128103.html