http://acm.fzu.edu.cn/problem.php?pid=2270
【题意】
给定6到10个点,从中选出6个不同的点组成两个三角形,使其中一个三角形可以通过另一个三角形平移和旋转得到。问有多少种不同的三角形选法?
【思路】
- 全等
- 排除对称
【Accepted】
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 using namespace std; 9 10 int n; 11 const double eps=1e-6; 12 struct Point 13 { 14 int x; 15 int y; 16 Point(){} 17 Point(int _x,int _y):x(_x),y(_y){} 18 Point operator-(const Point &b)const 19 { 20 return Point(x-b.x,y-b.y); 21 } 22 int operator^(const Point &b)const 23 { 24 return x*b.y-y*b.x; 25 } 26 int operator*(const Point &b)const 27 { 28 return x*b.x+y*b.y; 29 } 30 }p[12]; 31 bool v[11][11][11][11][11][11]; 32 int dist(int i,int j) 33 { 34 return (p[i]-p[j])*(p[i]-p[j]); 35 } 36 int dis[12][12]; 37 bool judge(int i,int j,int k) 38 { 39 double x=sqrt(dist(i,j)); 40 double y=sqrt(dist(i,k)); 41 double z=sqrt(dist(j,k)); 42 double a[3]={x,y,z}; 43 sort(a,a+3); 44 if(fabs(a[0]+a[1]-a[2])<=eps) 45 { 46 return false; 47 } 48 return true; 49 } 50 51 bool check(int i,int j,int k,int l,int m,int o,int flag) 52 { 53 int a[3]={i,k,m}; 54 int b[3]={j,l,o}; 55 sort(a,a+3); 56 sort(b,b+3); 57 if(v[a[0]][a[1]][a[2]][b[0]][b[1]][b[2]]) 58 { 59 return true; 60 } 61 if(flag) 62 { 63 v[a[0]][a[1]][a[2]][b[0]][b[1]][b[2]]=1; 64 } 65 return false; 66 } 67 68 bool rt(int i,int j,int k,int l,int m,int o) 69 { 70 if(((p[k]-p[i])^(p[m]-p[k]))*((p[l]-p[j])^(p[o]-p[l]))<0)//叉积的乘积大于等于0代表方向是一样的,如果方向不一样,说明是对称的 71 { 72 return false; 73 } 74 if(((p[m]-p[k])^(p[i]-p[m]))*((p[o]-p[l])^(p[j]-p[o]))<0) 75 { 76 return false; 77 } 78 if(((p[i]-p[m])^(p[k]-p[i]))*((p[j]-p[o])^(p[l]-p[j]))<0) 79 { 80 return false; 81 } 82 return true; 83 } 84 int main() 85 { 86 int T; 87 scanf("%d",&T); 88 int cas=0; 89 while(T--) 90 { 91 //这个数组用来去重,一定要初始化 92 memset(v,0,sizeof(v)); 93 int ans=0; 94 scanf("%d",&n); 95 for(int i=1;i<=n;i++) 96 { 97 scanf("%d%d",&p[i].x,&p[i].y); 98 } 99 for(int i=1;i<=n;i++) 100 { 101 for(int j=1;j<=n;j++) 102 { 103 if(j==i) continue; 104 for(int k=1;k<=n;k++) 105 { 106 if(k==i||k==j) continue; 107 for(int l=1;l<=n;l++) 108 { 109 if(l==i||l==j||l==k) continue; 110 if(dist(i,k)!=dist(j,l)) continue; 111 //目前为止已经选出两个三角形对应相等的两条边ik和jl 112 for(int m=1;m<=n;m++) 113 { 114 if(m==i||m==j||m==k||m==l) continue; 115 //先选出m点,排除三点共线的情况 116 if(!judge(i,k,m)) continue; 117 for(int o=1;o<=n;o++) 118 { 119 if(o==i||o==j||o==k||o==l||o==m) continue; 120 if(dist(k,m)!=dist(l,o)||dist(m,i)!=dist(o,j)) continue; 121 //现在已经选出两个全等的三角形 122 if(check(i,j,k,l,m,o,0)) continue; 123 //去重,如果是重复的重新选择 124 if(rt(i,j,k,l,m,o))//因为只能是平移和旋转得到,所以要排除对称这种情况 125 { 126 ans++; 127 check(i,j,k,l,m,o,1);//把这种选择标记为1 128 } 129 } 130 } 131 } 132 } 133 } 134 } 135 printf("Case %d: %d ",++cas,ans); 136 } 137 return 0; 138 }