题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1018
题意:平面上有n个点,一次可以擦掉一条直线上的所有点。问至少擦多少次才能将所有点擦完?
思路:b[i][j]表示经过第i、j个点的直线经过的所有点的集合。然后记忆化搜索即可。。。一开始我用b数组(一开始用的是一维数组)
View Code
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define min(x,y) ((x)<(y)?(x):(y)) 5 using namespace std; 6 7 struct Node 8 { 9 int x,y; 10 }; 11 12 const int INF=1000000000; 13 Node a[20]; 14 int n,f[(1<<16)+5],b[20][20],p[(1<<16)+5]; 15 int C,num=0; 16 17 void deal() 18 { 19 int i,j; 20 for(i=0;i<(1<<16);i++) 21 { 22 p[i]=0; 23 for(j=0;j<16;j++) if(i&(1<<j)) p[i]++; 24 } 25 } 26 27 inline int OK(Node a,Node b,Node c) 28 { 29 return (a.x-b.x)*(a.y-c.y)==(a.y-b.y)*(a.x-c.x); 30 } 31 32 void init() 33 { 34 int i,j,k; 35 memset(b,0,sizeof(b)); 36 for(i=0;i<n;i++) for(j=i+1;j<n;j++) 37 { 38 for(k=0;k<n;k++) if(OK(a[i],a[j],a[k])) 39 b[i][j]|=(1<<k); 40 } 41 } 42 43 int DFS(int st) 44 { 45 if(f[st]!=-1) return f[st]; 46 int i,j; 47 if(p[st]==0) return f[st]=0; 48 if(p[st]<=2) return f[st]=1; 49 f[st]=INF; 50 for(i=0;i<n;i++) if(st&(1<<i)) 51 { 52 for(j=i+1;j<n;j++) if(st&(1<<j)) 53 { 54 f[st]=min(f[st],1+DFS(st-(st&b[i][j]))); 55 } 56 break; 57 } 58 return f[st]; 59 } 60 61 int main() 62 { 63 deal(); 64 for(scanf("%d",&C);C--;) 65 { 66 scanf("%d",&n); 67 int i; 68 for(i=0;i<n;i++) scanf("%d%d",&a[i].x,&a[i].y); 69 init(); 70 memset(f,-1,sizeof(f)); 71 printf("Case %d: %d\n",++num,DFS((1<<n)-1)); 72 } 73 return 0; 74 }