题目大意:在二维平面坐标系上给你n的点,问你最少能用几条直线把他们都包括里面;
题目解析:首先我们要预处理所有的直线出来,令s[i][j]表示由点i和点j所确定的直线能经过的点的集合,为此我们需要暴力n^3处理出来,接下来就是状态dp了,如果我们不用记忆化搜索DFS就会超时,所以只能DFS了,DFS中的break很关键,很抽象需要自行体会;
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
using namespace std;
const int inf=0x3fffffff;
int dp[1<<16],n;
struct point
{
int x,y;
}p[16];
int s[17][17];
int dfs(int st)
{
if(!st) return dp[st]=0;
if(dp[st]!=inf) return dp[st];
int temp=st,cnt=0;
while(temp!=0)
{
cnt+=temp%2;
temp/=2;
}
if(cnt<=2)
return dp[st]=1;
int ans=inf,i,j;
for(i=0;i<n;i++)
{
if(st&(1<<i))
{
for(j=i+1;j<n;j++)
{
if(st&(1<<j))
{
ans=min(ans,dfs(st^(st&s[i][j]))+1);
}
}
break;
}
}
return dp[st]=ans;
}
int main()
{
int cas,c,i,j,k,l,len,cnt,temp;
cin>>cas;
for(c=1;c<=cas;c++)
{
memset(s,0,sizeof(s));
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d%d",&p[i].x,&p[i].y);
}
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
for(k=0;k<n;k++)
{
if((p[i].y-p[j].y)*(p[i].x-p[k].x)==(p[i].y-p[k].y)*(p[i].x-p[j].x))
s[i][j]=s[j][i]|=(1<<k);
}
}
}
len=1<<n;
for(i=0;i<len;i++)
dp[i]=inf;
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
if(s[i][j]!=0)
dp[s[i][j]]=1;
}
printf("Case %d: %d\n",c,dfs(len-1));
}
return 0;
}