没啥别的想法,感觉就是搜索,经过原点的抛物线已知两个点就可以求出解析式,在还没有被打下来的两个猪之间随意配对,确定解析式之后标记在这个抛物线下被打下来的猪。
猪也可以单独用一个抛物线打下来。
和之前写斗地主的搜索模式差不多,$TLE60pts$
就是要注意一下精度问题,$get$一个新点:浮点数的判等不能用$==$,可能会有精度误差,只差一点点的情况下可以认为他们是相等的,精度大概就取$EPS=1e-8$
bool dy(double a,double b) {//浮点误差 return Abs(a-b)<EPS; }
1 //暴搜 60pts 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstring> 6 #include<queue> 7 #include<map> 8 #include<iostream> 9 using namespace std; 10 #define ll long long 11 #define INF 0x3f3f3f3f 12 #define N 20 13 #define EPS 1e-8 14 double Abs(double a) 15 { 16 if(a>=0.0) return a; 17 return -a; 18 } 19 bool dy(double a,double b) 20 {//浮点误差 21 return Abs(a-b)<EPS; 22 } 23 int rd() 24 { 25 int f=1,s=0;char c=getchar(); 26 while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();} 27 while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+(c^48);c=getchar();} 28 return f*s; 29 } 30 int n,m,ans; 31 struct node{ 32 double x,y; 33 }pt[N]; 34 bool vis[N]; 35 int tmp[N],cnt; 36 void dfs(int k)//发射小鸟的次数 37 { 38 if(k>ans) return ; 39 for(int i=1;i<=n;i++) 40 { 41 if(vis[i]) continue; 42 vis[i]=1; 43 for(int j=i+1;j<=n;j++) 44 { 45 if(vis[j]) continue; 46 double x1=pt[i].x,x2=pt[j].x,y1=pt[i].y,y2=pt[j].y; 47 double a=(y1*x2-y2*x1)/(x1*x2*x1-x1*x2*x2); 48 if(a>=0) continue;//vis[j]=1要放在这个后面 否则不构成继续递归的条件也还是标记了 49 double b=(y1*x2*x2-y2*x1*x1)/(x1*x2*x2-x1*x1*x2); 50 //queue<int>Q; 51 //while(!Q.empty()) Q.pop(); 52 cnt=0; 53 vis[j]=1; 54 for(int p=1;p<=n;p++) 55 if(dy(pt[p].x*pt[p].x*a+pt[p].x*b,pt[p].y)) 56 { 57 vis[p]=1; 58 tmp[++cnt]=p; 59 //Q.push(p); 60 } 61 dfs(k+1); 62 vis[j]=0; 63 for(int i=1;i<=cnt;i++) 64 vis[tmp[i]]=0; 65 cnt=0; 66 /*while(!Q.empty()) 67 { 68 int u=Q.front();Q.pop(); 69 vis[u]=0; 70 }*/ 71 } 72 vis[i]=0; 73 } 74 for(int i=1;i<=n;i++) 75 if(!vis[i]) k++; 76 ans=min(ans,k); 77 return ; 78 } 79 int main() 80 { 81 int T=rd(); 82 while(T--) 83 { 84 n=rd(),m=rd(); 85 for(int i=1;i<=n;i++) 86 scanf("%lf %lf",&pt[i].x,&pt[i].y),vis[i]=0; 87 if(n==1) 88 { 89 puts("1"); 90 continue; 91 } 92 if(n==2) 93 { 94 /* 95 x1*x1*x2*a+x1*x2*b=y1*x2 96 x2*x2*x1*a+x2*x1*b=y2*x1 97 (x1*x1*x2-x1*x2*x2)a=y1*x2-y2*x1 98 x1*x2*(x1-x2)a=y1*x2-y2*x1 99 */ 100 if(((pt[1].x*pt[2].x*(pt[1].x-pt[2].x))*(pt[1].y*pt[2].x-pt[2].y*pt[1].x))<0) 101 puts("1"); 102 else puts("2"); 103 continue; 104 } 105 if(m==0||m==2) 106 { 107 ans=n; 108 //for(int i=1;i<=n;i++) 109 // printf("%f %f %d ",pt[i].x,pt[i].y,vis[i]); 110 dfs(0); 111 printf("%d ",ans); 112 } 113 if(m==1) 114 { 115 ans=((n+2)/3+1); 116 dfs(0); 117 printf("%d ",ans); 118 } 119 } 120 return 0; 121 }
然后,改用了以猪头作为...线索(?姑且这么叫着吧,找不到什么更好的词)
把抛物线和没有放抛物线的猪头存下来,每次遍历到猪头的时候就看这个猪头有没有在抛物线上,如果有就不用管他。没有就考虑把这个猪头和前面没有打下来的猪头放在一起看能否组成一个新的开口向下的抛物线,或者让他单着。
感觉每次把前面的猪头取出来放回去的操作改成链表的话,就很想$DLX$了呢。
这种写法可以过,但是我不会证复杂度什么的。
机房$dalao$说用$DLX$+迭代加深不能过....我...也很疑惑...
1 #include<cstdio> 2 #include<algorithm> 3 #include<vector> 4 #include<cstring> 5 #include<queue> 6 #include<map> 7 #include<iostream> 8 using namespace std; 9 #define ll long long 10 #define INF 0x3f3f3f3f 11 #define N 20 12 #define EPS 1e-8 13 double Abs(double a) 14 { 15 if(a>=0.0) return a; 16 return -a; 17 } 18 bool dy(double a,double b) 19 {//浮点误差 20 return Abs(a-b)<EPS; 21 } 22 int rd() 23 { 24 int f=1,s=0;char c=getchar(); 25 while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();} 26 while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+(c^48);c=getchar();} 27 return f*s; 28 } 29 int n,m,ans; 30 struct node{ 31 double x,y; 32 }pt[N]/*猪*/,pwx[N]/*抛物线*/; 33 int id[N];//单独的猪的标号 34 void dfs(int k,int u/*抛物线*/,int v/*单独的猪*/) 35 { 36 if(u+v>=ans) return ; 37 if(k>n) 38 { 39 ans=min(ans,u+v); 40 return ; 41 } 42 bool flag=0; 43 for(int i=1;i<=u;i++) 44 if(dy(pwx[i].x*pt[k].x*pt[k].x+pwx[i].y*pt[k].x,pt[k].y)) 45 { 46 dfs(k+1,u,v); 47 flag=1; 48 break; 49 } 50 if(flag) return ;//如果已经可以被打掉,就不用管了 51 //否则就 要么和其它猪形成抛物线 要么自己单独 52 double x1=pt[k].x,y1=pt[k].y; 53 for(int i=1;i<=v;i++) 54 { 55 double x2=pt[id[i]].x,y2=pt[id[i]].y; 56 if(dy(x1,x2)) continue; 57 double a=(y1*x2-y2*x1)/(x1*x2*x1-x1*x2*x2); 58 if(a>=0) continue; 59 double b=(y1*x2*x2-y2*x1*x1)/(x1*x2*x2-x1*x1*x2); 60 pwx[u+1].x=a,pwx[u+1].y=b; 61 int tmp=id[i]; 62 for(int j=i;j<v;j++) 63 id[j]=id[j+1]; 64 dfs(k+1,u+1,v-1); 65 for(int j=v;j>i;j--) 66 id[j]=id[j-1]; 67 id[i]=tmp; 68 } 69 id[v+1]=k; 70 dfs(k+1,u,v+1); 71 } 72 int main() 73 { 74 int T=rd(); 75 while(T--) 76 { 77 n=rd(),m=rd(); 78 for(int i=1;i<=n;i++) 79 scanf("%lf %lf",&pt[i].x,&pt[i].y); 80 if(n==1) 81 { 82 puts("1"); 83 continue; 84 } 85 if(n==2) 86 { 87 if(((pt[1].x*pt[2].x*(pt[1].x-pt[2].x))*(pt[1].y*pt[2].x-pt[2].y*pt[1].x))<0) 88 puts("1"); 89 else puts("2"); 90 continue; 91 } 92 ans=n; 93 dfs(1,0,0); 94 printf("%d ",ans); 95 } 96 return 0; 97 }
至于正解的什么状压,不如...放飞象征和平的鸽子?