东北大学第二场算法题解报告

7-1 N个数求和

题解
按照小学学的分数,将输入的分数全部通分,然后分子分母求最大公约数化简
由题目知分数输入的时候均以 分子/分母 给出,我们可以利用 scanf 中的格式符进行输入
代码

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long gcd(long long x,long long y)
{
if(y<0)return gcd(x,-y);
if(!y)return x;
else return gcd(y,x%y);
}
struct FS{
long long Fz,Fm;
}a[105];
long long FFm=1,FFz=0;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%lld/%lld",&a[i].Fz,&a[i].Fm);
for(int i=1;i<=n;++i)
{
long long k=gcd(FFm,a[i].Fm);
FFm=FFm/k*a[i].Fm;//求出所有分母的最小公倍数
}
for(int i=1;i<=n;++i)FFz+=FFm/a[i].Fm*a[i].Fz;//通分后的分子求和
if(!FFz)//分子为0的情况
{
printf("0");
return 0;
}
long long ZZZ=gcd(FFm,FFz);
FFm/=ZZZ;
FFz/=ZZZ;
if(FFz*FFz<FFm*FFm)//分子绝对值小于分母绝对值的情况
{
printf("%lld/%lld",FFz,FFm);
return 0;
}
long long A,B;
B=FFz%FFm;
A=FFz/FFm;
printf("%lld",A);
if(B)printf(" %lld/%lld",B,FFm);
return 0;
}

7-2 比较大小

题解
我这怎么写题解……
可以使用C艹的algorithm里面的sort搞个排序真实大材小用
也可以手写冒泡真实大材小用*2
也可以分类讨论
或者搞个二叉搜索树啥的(x)
代码

7-3 A-B

题解
读入两个字符串,同时申请一个大小为128的布尔(bool)型数组
(可见的ASCII码和空白字符在ascii码表上占据32~126)
先读入两个字符串,并单独扫一遍B字符串,B字符串出现过的字符在之前申请的bool型数组上做标记
再逐个字符检查A字符串,当检查的字符没在布尔型数组上做过标记的时候才输出
代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int a[3];
int main()
{
scanf("%d%d%d",&a[0],&a[1],&a[2]);
sort(a,a+3);//我偷懒了直接丢了个sort上去
printf("%d->%d->%d",a[0],a[1],a[2]);
return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char A[10005];
char B[10005];
bool N[128];
## 7-4 计算指数
题解
n不超过10,直接暴力循环可得也不会TLE
(但建议学习一下快速幂算法,代码中使用的即为快速幂算法)
代码
int main()
{
for(int i=0;;++i)
{
A[i]=getchar();
if(A[i]=='\n')break;
}
for(int i=0;;++i)
{
B[i]=getchar();
if(B[i]=='\n')break;
}
for(int i=0;B[i]!='\n';++i)N[(int)B[i]]=true;
for(int i=0;A[i]!='\n';++i)
{
if(!N[A[i]])printf("%c",A[i]);
}
return 0;
}
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int Pow4(int a,int b)
{
int r=1;
while(b)
{
if(b&1)r*=a;
a*=a;
b>>=1;
}
return r;
}
int main()
{
int n;
scanf("%d",&n);
printf("2^%d = %d",n,Pow4(2,n));
return 0;
}

7-5 计算阶乘和

题解
直接循环暴力求解即可
代码

7-6 简单题

题解
此题+岩浆=黑曜石
直接输出即可
代码

7-7 跟奥巴马一起画方块

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int main()
{
int n,t=1,S=0;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
t*=i;
S+=t;
}
printf("%d",S);
return 0;
}
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int main()
{
printf("This is a simple problem.");
return 0;
}

题解
我咋感觉这个题之前在学校做过
按照题目要求循环就好了
代码

7-8 查验身份证

题解
按照题目要求直接做就好了
(别忘了申请两个常数数组把加的权和对应的码放进去)
代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
char a;
int main()
{
int n,x;
scanf("%d %c",&n,&a);
x=(n+1)/2;
for(int i=1;i<=x;++i)
{
for(int j=1;j<=n;++j)
{
printf("%c",a);
}
printf("\n");
}
return 0;
}

7-9 集合相似度

题解
其实也是个按照题面做就行的题,不过群里有人说超时,我在这说点解决方法
输入结束后将每个集合内的数据从小到大排序(推荐学习一下快速排序,C艹用户可直接使用STL内的
sort)
然后将集合内重复数据去除(可以暴力做,C艹用户可直接使用STL内的unique)
这样每个集合的大小都是已知的
排序的用途:找相同数据数目的时候,可以先定义两个变量i,j。
分别指代两个数组(下文分别称之为A,B)的下标(i,j别忘记初始化)
然后如果A[i]>B[j],我们只需要将j+=1;
同理,如果A[i]<B[j] ,我们只需要将i+=1。
A[i]==B[j]时,我们计数+=1(即Nc+=1)同时i+=1, j+=1
当任意一个下标扫完整个数组后停止寻找
(因为此时每个数组内的数据是由小到大排序的且无重复数据,若A[i]>B[j] ,那么B数组内有可能等于
A[i]的数据只可能在B[j]之后,若B数组检查完毕,则A当前数字以及之后的数组均不存在与B数组中,反
过来也是同理,不再赘述)
此时计算Nc所需时间为O(min(A数组元素数目,B数组元素数目))

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const char ST[11]={'1','0','X','9','8','7','6','5','4','3','2'};
const int St[17]={7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
char A[20];
int main()
{
int n;
bool OK=true;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%s",A);
int Tem=0;
bool OK2=true;
for(int j=0;j<17;++j)
{
if(A[j]>='0'&&A[j]<='9')
{
Tem+=(A[j]-'0')*St[j];
}
else
{
OK2=false;
break;
}
}
Tem%=11;
if(!OK2||ST[Tem]!=A[17])
{
printf("%s\n",A);
OK=false;
continue;
}
}
if(OK)printf("All passed");
return 0;
}

Nt=两个数组元素数目之和-Nc
代码

7-10 树的遍历

解题必备知识
二叉树的定义,二叉树先序、中序、后序和层序遍历的定义与性质

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[51][10005];
int main()
{
int N,K;
scanf("%d",&N);
for(int i=1;i<=N;++i)
{
int M;
scanf("%d",&M);
for(int j=1;j<=M;++j)
{
scanf("%d",&a[i][j]);
}
sort(a[i]+1,a[i]+M+1);
a[i][0]=unique(a[i]+1,a[i]+M+1)-&a[i][1];
}
scanf("%d",&K);
while(K--)
{
int ta,tb;
scanf("%d%d",&ta,&tb);
int Nc=0,Nt=a[ta][0]+a[tb][0];
for(int i=1,j=1;i<=a[ta][0]&&j<=a[tb][0];)
{
if(a[ta][i]==a[tb][j])
{
Nc++;
i++;
j++;
continue;
}
if(a[ta][i]>a[tb][j])j++;
else i++;
}
Nt-=Nc;
double ans=((double)Nc)/((double)Nt)*100;
printf("%.2lf%%\n",ans);
}
return 0;
}

(推荐的网址: https://blog.csdn.net/qq_42475914/article/details/84311235
题解
二叉树前序遍历是先输出当前遍历节点,再按照左子树右子树顺序遍历
二叉树中序遍历是先遍历左子树,再输出当前遍历节点,再遍历右子树
二叉树后序遍历是先按照左子树右子树顺序遍历,再输出当前遍历节点
二叉树层序遍历是按照二叉树的深度从左往右进行输出
于是我们可知,后序遍历序列的最后一个数字是根节点
我们就可以对照中序遍历序列找出其左右子树长度,按照长度再后序遍历序列中找出其子树的后序遍历即可。
代码

#include<iostream>
#include<cstdio>
using namespace std;
int H[35],Z[35];
int ans[35][35];
void dfs(int H_l,int H_r,int Z_l,int Z_r,int cnt)
{
ans[cnt][0]++;
ans[cnt][ans[cnt][0]]=H[H_r];
for(int i=Z_l;i<=Z_r;++i)
{
if(Z[i]==H[H_r])
{
if(i-1>=Z_l)dfs(H_l,H_l+i-Z_l-1,Z_l,i-1,cnt+1);
if(i+1<=Z_r)dfs(H_l+i-Z_l,H_r-1,i+1,Z_r,cnt+1);
}
}
return;
}
int main()
{
int N;
scanf("%d",&N);
for(int i=1;i<=N;++i)scanf("%d",&H[i]);
for(int i=1;i<=N;++i)scanf("%d",&Z[i]);
dfs(1,N,1,N,1);
for(int i=1;ans[i][0]!=0;++i)
{
for(int j=1;j<=ans[i][0];++j)
{
printf("%d",ans[i][j]);
if(j!=ans[i][0]||ans[i+1][0]!=0)printf(" ");
}
}
return 0;
}

7-11 家庭房产

题解
使用并查集算法将不同人的信息进行合并,最后输出信息即可
并查集
在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询
问题。
有一个联合查找算法(union-find algorithm)定义了两个用于此数据结构的操作:
·Find:确定元素属于哪一个子集。这个确定方法就是不断向上查找找到它的根节点,它可以被用来确
定两个元素是否属于同一子集。
·Union:将两个子集合并成同一个集合。
(定义来自网络,其实还有一个judge操作)
代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct PEO{
int id;
int num_house,num_family,num_S;
double PJ_house()const
{
return ((double)num_house)/((double)num_family);
}
double PJ_S()const
{
return ((double)num_S)/((double)num_family);
}
bool operator<(const PEO &b) const
{
if(PJ_S()!=b.PJ_S())return PJ_S()>b.PJ_S();
else return id<b.id;
}
}A[10000];
int Find(int x)//并查集
{
if(A[x].id!=x)A[x].id=Find(A[x].id);
return A[x].id;
}
void unioon(int x,int y)
{
x=Find(x);
y=Find(y);
if(x==y)return;
if(x>y)swap(x,y);
A[y].id=x;
A[x].num_family+=A[y].num_family;
A[x].num_house+=A[y].num_house;
A[x].num_S+=A[y].num_S;
A[y].num_S=-1;
}

7-12 最长对称子串

int main()
{
int N;
scanf("%d",&N);
for(int i=0;i<=9999;++i)//无论数据中有没有,凡是提到了就算一口人
{
A[i].id=i;
A[i].num_family=1;
A[i].num_house=0;
A[i].num_S=0;
}
for(int i=1;i<=N;++i)
{
scanf("%d%d%d%d",&CZ[i][1],&CZ[i][2],&CZ[i][3],&CZ[i][4]);
vis[CZ[i][1]]=true;
if(CZ[i][2]!=-1)vis[CZ[i][2]]=true;
if(CZ[i][3]!=-1)vis[CZ[i][3]]=true;
for(int j=1;j<=CZ[i][4];++j)
{
scanf("%d",&CZ[i][4+j]);
vis[CZ[i][4+j]]=true;
}
scanf("%d%d",&A[CZ[i][1]].num_house,&A[CZ[i][1]].num_S);
}
for(int i=1;i<=N;++i)
{
if(CZ[i][2]!=-1)unioon(CZ[i][1],CZ[i][2]);
if(CZ[i][3]!=-1)unioon(CZ[i][1],CZ[i][3]);
for(int j=1;j<=CZ[i][4];++j)
{
unioon(CZ[i][1],CZ[i][4+j]);
}
}
sort(A,A+10000);
int cnt=0;
while(vis[A[cnt].id])cnt++;//判断有几户人家
printf("%d\n",cnt);
for(int i=0;i<cnt;++i)
{
printf("%04d %d %.3lf
%.3lf\n",A[i].id,A[i].num_family,A[i].PJ_house(),A[i].PJ_S());
}
return 0;
}

题解
1.马拉车算法(Manacher‘s Algorithm),时间复杂度为O(N)
2.本题解中代码:使用动态规划,时间复杂度为O(N^2)
定义:s[i,j]是字符串s由下标i到下标j的字符组成的字符串
dp[i,j]判断s[i,j]是否是回文串
易知, dp[i,j]=true的条件是dp[i+1,j-1]=true且s[i]==s[j]
然后跑一个二重循环,递推就可以了,每个回文串的长度则是j-i+1
代码

7-13 肿瘤诊断

题解
使用BFS求出每一个肿瘤的体积,再判断是否超过阈值即可
不要使用dfs,会出现堆栈溢出的情况
代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char A[1005];
bool t[1005][1005];
int main()
{
int ans=1;
int len=1;
while((A[len]=getchar())!=EOF)len++;
for(int i=1;i<=len;++i)t[i][1]=true;
for(int i=1;i<len;++i)if(A[i]==A[i+1])t[i][2]=true;
for(int i=3;i<=len;++i)
{
for(int j=1;j+i-1<=len;++j)
{
if(t[j+1][i-2]&&A[j]==A[j+i-1])
{
t[j][i]=true;
ans=i;
}
else t[j][i]=false;
}
}
printf("%d",ans);
return 0;
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
bool vis[1287][129][61];
bool mpa[1287][129][61];
const int xx[6]={1,-1,0,0,0,0};
const int yy[6]={0,0,1,-1,0,0};
const int zz[6]={0,0,0,0,1,-1};
int M,N,L,T;
struct point{
int x,y,z;
};
int dfs(int x,int y,int z)
{
int res=0;
vis[x][y][z]=true;
point st;
st.x=x;
st.y=y;
st.z=z;
queue<point>q1;
q1.push(st);
while(!q1.empty())
{
point w=q1.front();
q1.pop();
if(!mpa[w.x][w.y][w.z])continue;
res++;
for(int i=0;i<6;++i)
{
point tem=w;
tem.x+=xx[i];
tem.y+=yy[i];
tem.z+=zz[i];
if(tem.x>=1&&tem.x<=M&&tem.y>=1&&tem.y<=N&&tem.z>=1&&tem.z<=L&&!vis[tem.x]
[tem.y][tem.z])
{
q1.push(tem);
vis[tem.x][tem.y][tem.z]=true;
}
}
}
return res;
}
int main()
{
scanf("%d%d%d%d",&M,&N,&L,&T);
for(int k=1;k<=L;++k)
{
for(int i=1;i<=M;++i)
{
for(int j=1;j<=N;++j)
{
int t;
scanf("%d",&t);
if(t)mpa[i][j][k]=true;
else mpa[i][j][k]=false;
}
}
}
int ans=0;
for(int k=1;k<=L;++k)
{
for(int i=1;i<=M;++i)
{
for(int j=1;j<=N;++j)
{
if(vis[i][j][k])continue;
int tem=dfs(i,j,k);
if(tem>=T)ans+=tem;
}
}
}
printf("%d",ans);
return 0;
}

7-14 垃圾箱分布

题解
Gx表示的垃圾桶编号可以看做1000+x的节点(技巧)
这个题需要使用最短路算法,请自行百度
(推荐的网站:https://blog.csdn.net/strve/article/details/80957491)
①所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方
②如果解不唯一,则输出到所有居民点的平均距离最短的那个解
③如果这样的解还是不唯一,则输出编号最小的地点。
三句话决定排序关键字:
到居民楼最短距离最长的路径长度(降序)
总路径长度(升序)
编号(升序)
则序列的第一个符合到居民楼最短距离最长的路径长度< Ds的即为答案
代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
struct Edge{
int n,v;
long long w;
}edge[20005];
int head[1050],num_edge;
void add_edge(int u,int v,long long w)
{
num_edge++;
edge[num_edge].n=head[u];
edge[num_edge].v=v;
edge[num_edge].w=w;
head[u]=num_edge;
}
long long dis[1050];
bool vis[1050];
long long ans[15][3];//0 is max dis,1 is min dis,2 is total dis
int N,M,K;
long long D;
void SPFA(int u)
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int>q1;
q1.push(u);
vis[u]=true;
dis[u]=0;
while(!q1.empty())
{
int w=q1.front();
q1.pop();
vis[w]=false;
for(int i=head[w];i;i=edge[i].n)
{
if(dis[edge[i].v]>dis[w]+edge[i].w)
{
dis[edge[i].v]=dis[w]+edge[i].w;
if(!vis[edge[i].v])
{
vis[edge[i].v]=true;
q1.push(edge[i].v);
}
}
}
}
for(int i=1;i<=N;++i)
{
if(dis[i]>ans[u-1000][0])ans[u-1000][0]=dis[i];
ans[u-1000][2]+=dis[i];
}
ans[u-1000][1]=9223372036854775807LL;
for(int i=1;i<=N;++i)
{
if(dis[i]<ans[u-1000][1])ans[u-1000][1]=dis[i];
}
return;
}
int main()
{
scanf("%d%d%d%lld",&N,&M,&K,&D);
for(int i=1;i<=K;++i)
{
char A[10]={0},B[10]={0};
int a=0,b=0;
long long w;
bool a_g=false,b_g=false;
scanf("%s%s%lld",A,B,&w);
int len=strlen(A);
for(int j=0;j<len;++j)
{
if(A[j]=='G')a_g=true;
else
{
a*=10;
a+=A[j]-'0';
}
}
len=strlen(B);
for(int j=0;j<len;++j)
{
if(B[j]=='G')b_g=true;
else
{
b*=10;
b+=B[j]-'0';
}
}
if(a_g)a+=1000;
if(b_g)b+=1000;
add_edge(a,b,w);
add_edge(b,a,w);
}
for(int i=1;i<=M;++i)
{
SPFA(1000+i);
}
int ppd=-1;
for(int i=1;i<=M;++i)
{
if(ans[i][0]>D)continue;
if(ppd==-1)
{
ppd=i;
continue;
}
if(ans[i][1]>ans[ppd][1])ppd=i;
else if(ans[i][1]==ans[ppd][1]&&ans[i][2]<ans[ppd][2])
{
ppd=i;
}
}
if(ppd==-1)
{
printf("No Solution");
}
else
{
printf("G%d\n",ppd);
printf("%.1lf %.1lf",(double)ans[ppd][1],((double)ans[ppd]
[2]/(double)N));
}
return 0;
}

7-15 迎风一刀斩

题解
简单十分复杂的分类讨论
1.看输入的两个多边形端点数之和是否超过8或者是否有任意一个超过5,有则输出NO
2.看多边形与坐标轴平行的边数是否为端点数-1,如果不等于,看是否为两个矩形,若是两个矩形,再
看这两个矩形是否有边长相等;有则输出YES,除此之外边数不等于端点数-1的情况均输出NO
3.看多边形是否为凸多边形(可以凸包,也可以强行讨论(不同讨论方式情况不同,某种方式讨论出十
二种情况每种还巨麻烦)(自认为最优解是看多边形的非直角,五边形的需要2个钝角,四边形需要1钝
1锐,通过向量求cos即可)不是则输出NO)
4.如果两块残片都是有1条斜边的四边形,除了要检查两条斜边是否一致,还要检查两块残片内部的锐
角是否相等,如下图。
5.计算斜边斜率以及斜边长度,如果长度相等,且斜边平行/垂直或水平翻转的其中一条斜边与另一条平
行/垂直即为YES,否则为NO
这个题需要使用最短路算法,请自行百度
(推荐的网站:https://blog.csdn.net/strve/article/details/80957491)
①所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方
②如果解不唯一,则输出到所有居民点的平均距离最短的那个解
③如果这样的解还是不唯一,则输出编号最小的地点。

三句话决定排序关键字:
到居民楼最短距离最长的路径长度(降序)
总路径长度(升序)
编号(升序)
【则序列的第一个符合到居民楼最短距离最长的路径长度< Ds的即为答案】
(然后按照题目要求筛去不符合要求的答案即可)
代码

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int main()
{
int N;
scanf("%d",&N);
while(N--)
{
int a,b;
int A[15][2]={0},B[15][2]={0};
scanf("%d",&a);
for(int i=1;i<=a;++i)scanf("%d%d",&A[i][0],&A[i][1]);
A[a+1][0]=A[1][0];
A[a+1][1]=A[1][1];
scanf("%d",&b);
for(int i=1;i<=b;++i)scanf("%d%d",&B[i][0],&B[i][1]);
B[b+1][0]=B[1][0];
B[b+1][1]=B[1][1];
if(a>5||b>5||a+b>8)
{
printf("NO\n");
continue;
}
//判断直角数
int xa_id=0,xb_id=0;
int cnta=0,cntb=0;
for(int i=1;i<=a;++i)
{
if(A[i][0]==A[i+1][0]||A[i][1]==A[i+1][1])cnta++;
else xa_id=i;
}
for(int i=1;i<=b;++i)
{
if(B[i][0]==B[i+1][0]||B[i][1]==B[i+1][1])cntb++;
else xb_id=i;
}
if(cnta!=a-1||cntb!=b-1)
{
if(cnta==4&&cntb==4&&a==4&&b==4)//两个矩形特判
{
int len[3];
len[0]=max(A[1][0]>A[2][0]?A[1][0]-A[2][0]:A[2][0]-A[1][0],A[1]
[1]>A[2][1]?A[1][1]-A[2][1]:A[2][1]-A[1][1]);
len[1]=max(A[2][0]>A[3][0]?A[2][0]-A[3][0]:A[3][0]-A[2][0],A[2]
[1]>A[3][1]?A[2][1]-A[3][1]:A[3][1]-A[2][1]);
len[2]=max(B[1][0]>B[2][0]?B[1][0]-B[2][0]:B[2][0]-B[1][0],B[1]
[1]>B[2][1]?B[1][1]-B[2][1]:B[2][1]-B[1][1]);
if(len[0]==len[2]||len[1]==len[2])
{
printf("YES\n");
continue;
}
}
printf("NO\n");
continue;
}
if(a==5)//判断是否为凸多边形
{
long long xa,xb,ya,yb,xc,xd,yc,yd;
int t1=xa_id,t2=(xa_id)%a+1;
xa=A[t1][0]-A[t1+1][0];
xb=A[t1][0]-A[(t1+3)%a+1][0];
ya=A[t1][1]-A[t1+1][1];
yb=A[t1][1]-A[(t1+3)%a+1][1];
xc=A[t2][0]-A[t2+1][0];
xd=A[t2][0]-A[(t2+3)%a+1][0];
yc=A[t2][1]-A[t2+1][1];
yd=A[t2][1]-A[(t2+3)%a+1][1];
if(xa*xb+ya*yb>=0||xc*xd+yc*yd>=0)
{
printf("NO\n");
continue;
}
}
if(b==5)//判断是否为凸多边形
{
long long xa,xb,ya,yb,xc,xd,yc,yd;
int t1=xb_id,t2=(xb_id)%b+1;
xa=B[t1][0]-B[t1+1][0];
xb=B[t1][0]-B[(t1+3)%b+1][0];
ya=B[t1][1]-B[t1+1][1];
yb=B[t1][1]-B[(t1+3)%b+1][1];
xc=B[t2][0]-B[t2+1][0];
xd=B[t2][0]-B[(t2+3)%b+1][0];
yc=B[t2][1]-B[t2+1][1];
yd=B[t2][1]-B[(t2+3)%b+1][1];
if(xa*xb+ya*yb>=0||xc*xd+yc*yd>=0)
{
printf("NO\n");
continue;
}
}
if(a==4)//判断是否为凸多边形
{
long long xa,xb,ya,yb,xc,xd,yc,yd;
int t1=xa_id,t2=(xa_id)%a+1;
xa=A[t1][0]-A[t1+1][0];
xb=A[t1][0]-A[(t1+2)%a+1][0];
ya=A[t1][1]-A[t1+1][1];
yb=A[t1][1]-A[(t1+2)%a+1][1];
xc=A[t2][0]-A[t2+1][0];
xd=A[t2][0]-A[(t2+2)%a+1][0];
yc=A[t2][1]-A[t2+1][1];
yd=A[t2][1]-A[(t2+2)%a+1][1];
if((xa*xb+ya*yb>=0&&xc*xd+yc*yd>=0)||(xa*xb+ya*yb<0&&xc*xd+yc*yd<0))
{
printf("NO\n");
continue;
}
}
if(b==4)//判断是否为凸多边形
{
long long xa,xb,ya,yb,xc,xd,yc,yd;
int t1=xb_id,t2=(xb_id)%b+1;
xa=B[t1][0]-B[t1+1][0];
xb=B[t1][0]-B[(t1+2)%b+1][0];
ya=B[t1][1]-B[t1+1][1];
yb=B[t1][1]-B[(t1+2)%b+1][1];
xc=B[t2][0]-B[t2+1][0];
xd=B[t2][0]-B[(t2+2)%b+1][0];
yc=B[t2][1]-B[t2+1][1];
yd=B[t2][1]-B[(t2+2)%b+1][1];
if((xa*xb+ya*yb>=0&&xc*xd+yc*yd>=0)||(xa*xb+ya*yb<0&&xc*xd+yc*yd<0))
{
printf("NO\n");
continue;
}
}
long long len[7];
len[1]=(long long)(A[xa_id][0]-A[xa_id+1][0]);
len[2]=(long long)(A[xa_id][1]-A[xa_id+1][1]);
len[3]=len[1]*len[1]+len[2]*len[2];
len[4]=(long long)(B[xb_id][0]-B[xb_id+1][0]);
len[5]=(long long)(B[xb_id][1]-B[xb_id+1][1]);
len[6]=len[4]*len[4]+len[5]*len[5];
if(len[3]==len[6]&&
(len[1]*len[5]==len[2]*len[4]||len[2]*len[5]==len[1]*len[4]||len[1]*len[4]+len[2
]*len[5]==0||len[2]*len[4]+len[1]*len[5]==0))//判断斜边斜率
{
if(a==4&&b==4)//判断四边形是否有两个锐角相等
{
long long xa,xb,ya,yb,xc,xd,yc,yd;
long long Ax1,Ax2,Ay1,Ay2;
int t1=xa_id,t2=(xa_id)%a+1;
xa=A[t1][0]-A[t1+1][0];
xb=A[t1][0]-A[(t1+2)%a+1][0];
ya=A[t1][1]-A[t1+1][1];
yb=A[t1][1]-A[(t1+2)%a+1][1];
xc=A[t2][0]-A[t2+1][0];
xd=A[t2][0]-A[(t2+2)%a+1][0];
yc=A[t2][1]-A[t2+1][1];
yd=A[t2][1]-A[(t2+2)%a+1][1];
if(xa*xb+ya*yb>0)
{
Ax1=xa;
Ax2=xb;
Ay1=ya;
Ay2=yb;
}
else
{
Ax1=xc;
Ax2=xd;
Ay1=yc;
Ay2=yd;
}
long long xat,xbt,yat,ybt,xct,xdt,yct,ydt;
long long Bx1,Bx2,By1,By2;
int tt1=xb_id,tt2=(xb_id)%b+1;
xat=B[tt1][0]-B[tt1+1][0];
xbt=B[tt1][0]-B[(tt1+2)%b+1][0];
yat=B[tt1][1]-B[tt1+1][1];
ybt=B[tt1][1]-B[(tt1+2)%b+1][1];
xct=B[tt2][0]-B[tt2+1][0];
xdt=B[tt2][0]-B[(tt2+2)%b+1][0];
yct=B[tt2][1]-B[tt2+1][1];
ydt=B[tt2][1]-B[(tt2+2)%b+1][1];
if(xat*xbt+yat*ybt>0)
{
Bx1=xat;
Bx2=xbt;
By1=yat;
By2=ybt;
}
else
{
Bx1=xct;
Bx2=xdt;
By1=yct;
By2=ydt;
}
if((Ax1*Ax2+Ay1*Ay2)*(Ax1*Ax2+Ay1*Ay2)*(Bx1*Bx1+By1*By1)*
(Bx2*Bx2+By2*By2)!=(Bx1*Bx2+By1*By2)*(Bx1*Bx2+By1*By2)*(Ax1*Ax1+Ay1*Ay1)*
(Ax2*Ax2+Ay2*Ay2))
{
printf("NO\n");
continue;
}
}
printf("YES\n");
continue;
}
printf("NO\n");
}
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值