湖南大學第十四屆ACM程式設計大賽 K The Right-angled Triangles
連結:https://ac.nowcoder.com/acm/contest/338/K
來源:牛客網
題目描述
Consider the right-angled triangles with sides of integral length.
Give you the integral length of the hypotenuse of a right-angled triangle. Can it construct a right triangle with given hypotenuse c such that the two legs of the triangle are all . integral length?
輸入描述:
There are several test cases. The first line contains an integer T(1≤T≤1,000), T is the number of test cases. The following T lines contain T test cases, each line contains one test case. For each test case, there is an integer : c, the length of hypotenuse.(1≤c≤45,000).
輸出描述:
For each case, output Yes if it can construct a right triangle with given hypotenuse c and sides of integral length , No otherwise.
示例1
輸入
4 5 6 15 13
輸出
Yes No Yes Yes
題目大意:
考慮具有整型長度的直角三角形。
給出直角三角形斜邊的長度。它能不能構造一個直角三角形,斜邊c是已知的,使得三角形的兩條邊都是整數?
輸入描述:
有幾個測試用例。第一行包含一個整數T(1≤T≤1000),T是測試用例的數量。
下面的T行包含T個測試用例,每一行包含一個測試用例。對於每個測試用例,都有一個整數:c,斜邊的長度。(c 1≤≤45000)。
輸出描述:
對於每一種情況,如果它能構造出斜邊c和整型長度的直角三角形,則輸出Yes,否則輸出No。
示例1
輸入
4
5
6
15
13
輸出
Yes
No
Yes
Yes
分析:
有兩種方法:
1。暴力列舉:題目提供的可能測試資料相對較弱,所以可以利用列舉的方法列舉每一個整數進行嘗試,但列舉範圍要縮小到
i*i<=c/2;c/2以後的數跟之前就重複了,同時如果不縮小範圍的話就超時了。
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
long long c,n,ans,a,b;
cin>>n;//輸入測試次數
while(n--)
{
ans=0;
cin>>c;//輸入斜邊
c=c*c;
for(int i=1;i*i<=c/2;i++)//只需要嘗試c/2之前的即可,c/2之後的重複
{
a=sqrt(c-i*i);//求另一個直角邊,如果符合條件答案為1直接跳出迴圈
if(a*a==c-i*i)
{
ans=1;
break;
}
}
if(ans==1)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
}
2.這個題很容易想到的一個思路就是暴力列舉。是的,我們給的解題方法也是暴力列舉。但是,直接列舉的複雜度是O(c2),會超時(TLE)。所以我們需要將問題轉化一下,使得列舉的複雜度是O(c)。
• 如果三角形三邊滿足如下關係,則是直角三角形。
• a=m^2-n^2
• b=2mn
• c=m^2+n^2
解釋:這是本原勾股數 因為
a^2+b^2
=(m^4 + n^4)- 2×m^2×n^2+(2mn)^2
=(m^2+n^2)^2=c^2
• 所以如果斜邊長度能夠表示成2個正整數的平方和,則能使得三邊都是正整數。這樣列舉的複雜度是O( c)。
• 另外,如果斜邊長度是一個合數,其有一個因子能表示為2個正整數的平方和,那麼也能使得三邊都是正整數。比如c=15,有因
子5=12+22,那麼也是可以構成三邊全是整數的直角三角形,每邊長度乘以3即可。就是( 9, 12, 15)
#include <stdio.h>
#define N 45001
int MK[N]={0},SQ[213];
int i,j,k;
//MK陣列標記能否是整數三角形,為0表示不能,非0表示可以, SQ陣列記錄數的平方值
int main()
{
for(i=1;i<213;++i)
SQ[i]=i*i;
for(i=1;i<213;++i)
for(j=i+1;j<213&&(k=SQ[i]+SQ[j])<N;++j)
MK[k]=1; //所有能寫成2整數平方和的被標記為能
for(i=5;i<22501;++i)
if(MK[i]==1)
for(j=2;(k=j*i)<N;++j)
MK[k]=1; //所有含2整數平方和的因子的正整數被標記為能,類似於篩法求素數的思想
scanf("%d",&t);
while(t--)
{
scanf("%d",&c);
printf("%s\n",MK[c]?"Yes":"No");
}
return 0;
}