To_Heart—题解——数三角形
首先分析一下题目,知道我们的下标是无法成为单数的,所以要将(0,0)到(9,9)的空间看成(0,0)到(18,18)的,即将0.5个单位长度看成一个,所以得到以下代码:
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int xx,xxx,yy,yyy;
scanf("%d%d%d%d",&xx,&xxx,&yy,&yyy);
xx+=xx; //xx为x的横坐标,xxx为x的纵坐标,下面一样;
yy+=yy;
xxx+=xxx;
yyy+=yyy;//将单位长度×2;
}
然后我们需要定义一个a[i][j][k][l],其值为一表示如果i,j到k,l有火柴,否则相反。
我们知道,如果i,j到i+2,j+2有火柴棒,那么可以看为i,j到i+1,j+1,i+1,j+1到i+2,j+2都有一根火柴棒,那么我们可以在输入时就进行处理:
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int xx,xxx,yy,yyy;
scanf("%d%d%d%d",&xx,&xxx,&yy,&yyy);
xx+=xx; //xx为x的横坐标,xxx为x的纵坐标,下面一样;
yy+=yy;
xxx+=xxx;
yyy+=yyy; //将单位长度×2;
a[(xx+yy)/2][(xxx+yyy)/2][xx][xxx]=1; //中点定理:(i,j)和(k,l)的中点为(i+k)/2,(j+l)/2;
a[xx][xxx][(xx+yy)/2][(xxx+yyy)/2]=1; //为了后文统计方便,我们可以把(i,j)到(k,l)的火柴同时看成(k,l)到(i,j)的火柴;
a[(xx+yy)/2][(xxx+yyy)/2][yy][yyy]=1;
a[yy][yyy][(xx+yy)/2][(xxx+yyy)/2]=1;
a[xx][xxx][yy][yyy]=1;
a[yy][yyy][xx][xxx]=1;
}
那么我们又发现,如果(0,0)到(1,1)有火柴,且(1,1)到(2,2)有火柴,那么(0,0)到(2,2)也一定有火柴。
那么现在我们需要一个程序来判断共线。我们知道共线肯定会出现一根联通三点的直线,结合一下数学知识,不难发现共线其实就是一个一次函数,即y=ax+b(y为横坐标,x为纵坐标);
又结合数学知识,我们知道,一次函数可以是往上,即y随着x增大而增大,或是往下,即y随着x增大而减小;
那么我们只需要判断一下这两种情况就可以了:
bool PD(int x1,int y1,int x2,int y2,int x3,int y3){//判断坐标为(x1,y1),(x2,y2),(x3,y3)的三数是否共线;
if(x1-y1==x2-y2&&x2-y2==x3-y3) //y随着x变大而变大;
return 0;
if(x1+y1==x2+y2&&x2+y2==x3+y3) //y随着x变大而变小;
return 0;
return 1;
}
但我们发现平行线也是一种共线的情况,所以加上平行线的判定方式:
bool PD(int x1,int y1,int x2,int y2,int x3,int y3){
if((x1==x2&&x1==x3)||(y1==y2&&y2==y3))
return 0;
if(x1-y1==x2-y2&&x2-y2==x3-y3) //y随着x变大而变大;
return 0;
if(x1+y1==x2+y2&&x2+y2==x3+y3) //y随着x变大而变小;
return 0;
return 1;
}
那么,我们已经处理完了所有情况,只需要暴力枚举三个数的坐标,并判断他们之间是否都有火柴,还要确保他们不共线(共线没有意义);
完整代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[25][25][25][25]={};
bool f[25][25][25][25][25][25]={};
bool PD(int x1,int y1,int x2,int y2,int x3,int y3){
if((x1==x2&&x1==x3)||(y1==y2&&y2==y3))
return 1;
if(x1-y1==x2-y2&&x2-y2==x3-y3) //y随着x变大而变大;
return 1;
if(x1+y1==x2+y2&&x2+y2==x3+y3) //y随着x变大而变小;
return 1;
return 0;
}
int main(){
int n,ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int xx,xxx,yy,yyy;
scanf("%d%d%d%d",&xx,&xxx,&yy,&yyy);
xx+=xx; //xx为x的横坐标,xxx为x的纵坐标,下面一样;
yy+=yy;
xxx+=xxx;
yyy+=yyy; //将单位长度×2;
a[(xx+yy)/2][(xxx+yyy)/2][xx][xxx]=1;
a[xx][xxx][(xx+yy)/2][(xxx+yyy)/2]=1;
a[(xx+yy)/2][(xxx+yyy)/2][yy][yyy]=1;
a[yy][yyy][(xx+yy)/2][(xxx+yyy)/2]=1;
a[xx][xxx][yy][yyy]=1;
a[yy][yyy][xx][xxx]=1;
}
for(int i=0;i<=18;i++){
for(int j=0;j<=18;j++){
for(int k=0;k<=18;k++){
for(int l=0;l<=18;l++){
for(int r=0;r<=18;r++) {
for(int z=0;z<=18;z++) {
if(a[i][j][k][l]==1&&a[k][l][r][z]==1&&!(i==k&&j==l)&&!(k==r&&l==z)) { //暴力判断是否共线,如果有两个点相同,则没有判断的必要;
if(PD(i,j,k,l,r,z)){
a[i][j][r][z]=1;
a[r][z][i][j]=1;
}
}
}
}
}
}
}
}
for(int i=0;i<=19;i++){
for(int j=0;j<=19;j++){
for(int k=0;k<=19;k++){
for(int l=0;l<=19;l++){
for(int r=0;r<=19;r++){
for(int z=0;z<=19;z++){
if(a[i][j][k][l]&&a[i][j][r][z]&&a[k][l][r][z]&&!f[i][j][k][l][r][z]&&!PD(i,j,k,l,r,z)){ //暴力判断三角形是否成立
f[i][j][k][l][r][z]=1;
f[k][l][i][j][r][z]=1; //如果(i,j)->(k,l)->(r,z)为三角形,那么(k,l)->(i,j)->(r,z)也是,则没有再计算的必要;
f[r][z][i][j][k][l]=1;
f[r][z][k][l][i][j]=1;
f[i][j][r][z][k][l]=1;
f[k][l][r][z][i][j]=1; //同理;
ans++;
}
}
}
}
}
}
}
printf("%d\n",ans);
return 0;
}