题面
题意
给一些点,问最少可以用几条直线将他们全部覆盖.
方法
因为n<=16,故方法为状压dp
首先预处理出任意两条直线所能覆盖的点,之后枚举来更新状态
枚举方法
首先枚举状态(基本规律,这样效率更高),然后添加直线的一个端点为该状态下第一个未覆盖的点,枚举另外一个,并用这两点组成的直线来更新状态,这样复杂度仅为
O
(
n
∗
2
n
)
O(n*2^{n})
O(n∗2n)
若不先枚举状态,先枚举其中一个点,则无法利用状态来确定另外一个点,故不得不再枚举另外一个点,复杂度为
O
(
n
2
∗
2
n
)
O(n^{2}*2^{n})
O(n2∗2n).
代码
#include<bits/stdc++.h>
#define db double
#define N 70000
#define M 20
using namespace std;
int T,TT,n,dp[N],x[M],y[M],tmp,each[M][M],eve[M][M];
inline int read()
{
char ch=getchar();
int an=0,f=1;
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while('0'<=ch&&ch<='9'){
an=an*10+ch-'0';
ch=getchar();
}
return an*f;
}
inline bool pd(int u1,int v1,int u2,int v2,int u3,int v3)
{
if((v3-v1)*(u2-u1)==(v2-v1)*(u3-u1)) return 1;
return 0;
}
int main()
{
int i,j,k,l;
scanf("%d",&T);
TT=T;
each[1][1]=0;
each[2][1]=2;
each[2][2]=1;
each[3][1]=6;
each[3][2]=5;
each[3][3]=3;
each[4][1]=14;
each[4][2]=13;
each[4][3]=11;
each[4][4]=7;
each[5][1]=30;
each[5][2]=29;
each[5][3]=27;
each[5][4]=23;
each[5][5]=15;
each[6][1]=62;
each[6][2]=61;
each[6][3]=59;
each[6][4]=55;
each[6][5]=47;
each[6][6]=31;
each[7][1]=126;
each[7][2]=125;
each[7][3]=123;
each[7][4]=119;
each[7][5]=111;
each[7][6]=95;
each[7][7]=63;
each[8][1]=254;
each[8][2]=253;
each[8][3]=251;
each[8][4]=247;
each[8][5]=239;
each[8][6]=223;
each[8][7]=191;
each[8][8]=127;
each[9][1]=510;
each[9][2]=509;
each[9][3]=507;
each[9][4]=503;
each[9][5]=495;
each[9][6]=479;
each[9][7]=447;
each[9][8]=383;
each[9][9]=255;
each[10][1]=1022;
each[10][2]=1021;
each[10][3]=1019;
each[10][4]=1015;
each[10][5]=1007;
each[10][6]=991;
each[10][7]=959;
each[10][8]=895;
each[10][9]=767;
each[10][10]=511;
each[11][1]=2046;
each[11][2]=2045;
each[11][3]=2043;
each[11][4]=2039;
each[11][5]=2031;
each[11][6]=2015;
each[11][7]=1983;
each[11][8]=1919;
each[11][9]=1791;
each[11][10]=1535;
each[11][11]=1023;
each[12][1]=4094;
each[12][2]=4093;
each[12][3]=4091;
each[12][4]=4087;
each[12][5]=4079;
each[12][6]=4063;
each[12][7]=4031;
each[12][8]=3967;
each[12][9]=3839;
each[12][10]=3583;
each[12][11]=3071;
each[12][12]=2047;
each[13][1]=8190;
each[13][2]=8189;
each[13][3]=8187;
each[13][4]=8183;
each[13][5]=8175;
each[13][6]=8159;
each[13][7]=8127;
each[13][8]=8063;
each[13][9]=7935;
each[13][10]=7679;
each[13][11]=7167;
each[13][12]=6143;
each[13][13]=4095;
each[14][1]=16382;
each[14][2]=16381;
each[14][3]=16379;
each[14][4]=16375;
each[14][5]=16367;
each[14][6]=16351;
each[14][7]=16319;
each[14][8]=16255;
each[14][9]=16127;
each[14][10]=15871;
each[14][11]=15359;
each[14][12]=14335;
each[14][13]=12287;
each[14][14]=8191;
each[15][1]=32766;
each[15][2]=32765;
each[15][3]=32763;
each[15][4]=32759;
each[15][5]=32751;
each[15][6]=32735;
each[15][7]=32703;
each[15][8]=32639;
each[15][9]=32511;
each[15][10]=32255;
each[15][11]=31743;
each[15][12]=30719;
each[15][13]=28671;
each[15][14]=24575;
each[15][15]=16383;
each[16][1]=65534;
each[16][2]=65533;
each[16][3]=65531;
each[16][4]=65527;
each[16][5]=65519;
each[16][6]=65503;
each[16][7]=65471;
each[16][8]=65407;
each[16][9]=65279;
each[16][10]=65023;
each[16][11]=64511;
each[16][12]=63487;
each[16][13]=61439;
each[16][14]=57343;
each[16][15]=49151;
each[16][16]=32767;
while(T--)
{
n=read();
for(i=1;i<=(1 << n)-1;i++) dp[i]=M;
for(i=1;i<=n;i++)
{
scanf("%d",&x[i]);
scanf("%d",&y[i]);
}
for(i=1;i<=n;i++)
{
for(k=i+1;k<=n;k++)
{
tmp=(1 << (i-1))|(1 << (k-1));
for(l=i+1;l<=n;l++)
{
if(l==k) continue;
if(pd(x[i],y[i],x[k],y[k],x[l],y[l]))
{
tmp|=(1 << (l-1));
}
}
eve[i][k]=tmp;
}
}
for(j=0;j<(1 << n)-1;j++)
{
if(dp[j]==M) continue;
for(i=1;i<=n;i++)
{
if(!(j & (1 << (i-1)))) break;
}
for(k=i+1;k<=n;k++)
{
if((j&(1<<(k-1)))!=0) continue;
tmp=eve[i][k];
dp[j|tmp]=min(dp[j|tmp],dp[j]+1);
}
}
for(i=1;i<=n;i++)
{
dp[(1 << n)-1]=min(dp[(1 << n)-1],dp[each[n][i]]+1);
}
printf("Case %d: %d\n",TT-T,dp[(1 << n)-1]);
}
}