topcoder srm 738 div1 FindThePerfectTriangle(枚举)

Problem Statement

    
You are given the ints perimeter and area. Your task is to find a triangle with the following properties:

  • The coordinates of each vertex are integers between 0 and 3000, inclusive.
  • The perimeter of the triangle must be exactly perimeter, and its area must be exactly area.

If there are multiple solutions, you may choose any of them. Return a vector <int> with six elements: {x1, y1, x2, y2, x3, y3}, where (x1, y1), (x2, y2), and (x3, y3) are the coordinates of the vertices of your triangle. If there is no solution, return an empty vector <int> instead.

Definition

    
Class: FindThePerfectTriangle
Method: constructTriangle
Parameters: int, int
Returns: vector <int>
Method signature: vector <int> constructTriangle(int area, int perimeter)
(be sure your method is public)

Limits

    
Time limit (s): 2.000
Memory limit (MB): 256

Constraints

- area will be between 1 and 1,000,000, inclusive.
- perimeter will be between 1 and 1000, inclusive.

Examples

0)  
    
6
11
Returns: { }
There are no valid triangles with area 6 and perimeter 11.
1)  
    
6
12
Returns: {1, 1, 1, 4, 5, 4 }
The example output describes a right triangle with vertices at (1, 1), (1, 4) and (5, 4). Its sides have lengths 3, 4, and 5, hence its perimeter is 12. The area of the triangle is (3*4)/2 = 6.
2)  
    
37128
882
Returns: {137, 137, 273, 410, 1, 410 }
 
3)  
    
12
18
Returns: {1, 1, 4, 5, 1, 9 }
In this test case our solution constructed an isosceles triangle with vertices at (1, 1), (4, 5) and (1, 9).
4)  
    
18096
928
Returns: {1, 1, 1, 88, 417, 88 }
 
5)  
    
1000000
1000
Returns: { }
 

This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.

题意

给出三角形的面积和周长,找到三个坐标为整数的点,使得以它们为顶点的三角形符合条件,并满足$$$1\le x_i\le 3000, 1\le y_i\le 3000, (i=1,2,3)$$$

分析

假设三条边的长度从大到小依次为$$$a, b, c$$$,通过枚举$$$a$$$和$$$b$$$,可以找到所有面积大小正确的组合。接下来的问题就是如何把这样的三角形放到网格上面。首先,$$$a^2$$$,$$$b^2$$$,$$$c^2$$$必须拆成两个平方数的和,因为周长≤$$$1000$$$,所以$$$a,b,c\lt 1000$$$,只需要对$$$1^2, 2^2,...,1000^2$$$进行预处理,记录它们所有拆成平方数的和的形式。对于一组$$$a, b, c$$$,遍历$$$a$$$和$$$b$$$的拆分方式的组合,假设把$$$a$$$这条边放到($$$0$$$,$$$0$$$)-($$$x_1$$$,$$$y_1$$$),$$$b$$$这条边放到($$$0$$$,$$$0$$$)-($$$x_2$$$, $$$y_2$$$),那么如果满足$$$c^2=(x_1-x_2)^2+(y_1-y_2)^2$$$,就找到了一组坐标。然后只需要把坐标平移到规定的区域内就行了。我选择的是所有坐标平移$$$x+1500,y+1500$$$

总结

第一场topcoder,从将近1点打到2点,熬夜场永远思路不清晰,暴力题都敲不出来(代码该怎么贴呀)

代码

#include<bits/stdc++.h>
using namespace std;
vector<pair<int, int>> cnt[1000006];
class FindThePerfectTriangle
{
    public:
    vector <int> constructTriangle(int area, int perimeter) {
        int  c;
        for (int i = 1; i <= 1000; ++i)cnt[i*i].emplace_back(i, 0);
        for (int i = 1; i <= 1000; ++i) {
            for (int j = 1; j<i&&j*j+i*i<=1000000; ++j) {
                if (cnt[i*i + j*j].empty())continue;
                cnt[i*i + j*j].emplace_back(i, j);
            }
        }
        for (int a = 1; a <= 1000 && a + 1 < perimeter; a++) {
            for (int b = 1; b <= 1000 && a + b < perimeter&&b <= a; b++) {
                c = perimeter - a - b;
                if (a < c || b < c || a >= (b + c))continue;
                //用海拉公式的变形来验证面积正确
                long long p = perimeter;
                long long s = p*(p - 2 * a)*(p - 2 * b)*(p - 2 * c);
                if (s == (long long)(16) * area*area) {
                    int A = a*a, B = b*b;
                    //枚举A和B的拆分方式
                    for (int i = 0; i<cnt[A].size(); i++)
                        for (int j = 0; j<cnt[B].size(); j++) {
                            int x1 = cnt[A][i].first, y1 = cnt[A][i].second;
                            int x2 = cnt[B][j].first, y2 = cnt[B][j].second;
                            int xx, yy;
                            for(int s1=-1;s1<=1;s1+=2)
                                for(int s2=-1;s2<=1;s2+=2){
                                    xx = x1 - s1*x2;
                                    yy = y1 - s2*y2;
                                    if(xx*xx+yy*yy==c*c){
                                        vector<int>res;
                                        res.push_back(1500); res.push_back(1500);
                                        res.push_back(1500+x1); res.push_back(1500+y1);
                                        res.push_back(1500+s1*x2); res.push_back(1500+s2*y2);
                                        return res;
                                    }
                                    xx = x1 - s1*y2;
                                    yy = y1 - s2*x2;
                                    if (xx*xx + yy*yy == c*c){
                                        vector<int>res;
                                        res.push_back(1500); res.push_back(1500);
                                        res.push_back(1500 + x1); res.push_back(1500 + y1);
                                        res.push_back(1500 + s1*y2); res.push_back(1500 + s2*x2);
                                        return res;
                                    }
                                }
                        }

                }
            }
        }
        vector<int>res;
        return res;
    }
};

原文地址:https://www.cnblogs.com/tobyw/p/9734428.html

时间: 2024-12-25 15:40:46

topcoder srm 738 div1 FindThePerfectTriangle(枚举)的相关文章

Topcoder SRM 643 Div1 250&lt;peter_pan&gt;

Topcoder SRM 643 Div1 250 Problem 给一个整数N,再给一个vector<long long>v; N可以表示成若干个素数的乘积,N=p0*p1*p2*......*pn,我们假设p0,p1,...,pn是单调不降的,那么v里存储的是下标为偶数 的N的质因数p0,p2,p4,...,p(2k).现在要求写一个程序,返回一个vector<long long>ans; ans里存储的是p0,p1,p2,...,pn. Limits Time Limit(m

Topcoder SRM 648 Div1 250

Problem 给一个长度为N的"AB"字符串S,S只含有两种字符'A' 或 'B',设pair(i,j)(0=<i<j<N)表示一对 i,j 使得S[i]='A',S[j]='B'.现给定一个K,求字符串S,使得pair(i,j)的个数恰好为K.若不存在,则返回空串. Limits Time Limit(ms): 2000 Memory Limit(MB): 256 N: [2, 50] K: [0 , N*(N-1)/2 ] Solution 若K>(N/2

Topcoder SRM 627 div1 HappyLettersDiv1 : 字符串

Problem Statement      The Happy Letter game is played as follows: At the beginning, several players enter the field. Each player has a lowercase English letter on their back. The game is played in turns. In each turn, you select two players with dif

Topcoder SRM 655 DIV1 500 FoldingPaper2 递归 + 枚举

题意:给你一张长W,宽H 的纸,问你能不能者成给定的大小, 每一次折纸只能折成整数大小. 解题思路:递推+枚举   枚举给定大小的长和宽,然后套进 W,H中求最小值  , 折纸策略最优是每次折半. 解题代码: 1 // BEGIN CUT HERE 2 /* 3 4 */ 5 // END CUT HERE 6 #line 7 "FoldingPaper2.cpp" 7 #include <cstdlib> 8 #include <cctype> 9 #incl

Topcoder SRM 603 div1题解

昨天刚打了一场codeforces...困死了...不过赶在睡前终于做完了- 话说这好像是我第一次做250-500-1000的标配耶--- Easy(250pts): 题目大意:有一棵树,一共n个节点,每个节点都有一个权值,两人A和B分别进行操作,由A先手,每人可以选择一条边,将它删掉得到两个联通块.游戏不断进行下去,最后只剩下一个节点.A希望最后的节点权值尽可能大,B希望尽可能小,求这个最后的值.数据保证n<=50. 这道题真的是博弈好题啊-(感觉放到ACM很合适啊) 我们考虑第一次A会如何选

topcoder srm 712 div1 -23

1.给定两个长度为$n$的数组$A,B$.有两种操作可以作用于数组$A$.第一种,将每个元素左侧的相邻数字加到其上:第二种,将每个元素右侧的相邻数字加到其上.0的左侧是$n-1$,$n-1$的右侧是0.比如1,2,3,4执行第一种操作后是5,3,5,7.给出一个不超过100的操作序列使得$A$变成$B$.$n \leq 50$. 思路:将$a_{0},a_{1},...,a_{n-1}$看做$a_{0}x^{0}+a_{1}x^{1}+...+a_{n-1}x^{n-1}$.那么第一种操作相当于

Topcoder SRM 345 Div1 250

题意:起初在(0,0),要到(x,y)去,每次只能横向或纵向移动.横向移动时,若所在直线y为偶数,那么只能往x轴正方向移动,若为奇数,只能往x轴反方向移动:纵向移动时,若所在直线x为偶数,那么只能往y轴正方向移动,若为奇数,只能往y轴反方向移动.问从起点到终点的最短距离是多少? x,y 范围是[-1e6, 1e6] 解法:一开始想到bfs(想到很自然),将(0, 0), (x, y), (x, 0), (0, y)这4个点分别周围9个点(包括自己)作为可达点.bfs处理出(0, 0)到(x, y

topcoder srm 360 div1

problem1 link (1)$n \neq m$时,假设$n<m$,那么同一行中的$m$个数字必定都相等. (2)$n=m$时,要满足任意的$i_{1},i_{2},j_{1},j_{2},A[i_{1}][j_{1}]+A[i_{2}][j_{2}]=A[i_{1}][j_{2}]+A[i_{2}][j_{1}]$ import java.util.*; import java.math.*; import static java.lang.Math.*; public class Su

topcoder srm 702 div1 -23

1.给定一个$n*m$的矩阵,里面的数字是1到$n*m$的一个排列.一个$n*m$矩阵$A$对应一个$n*m$ 的01字符串,字符串的位置$i*m+j$为1当且仅当$A_{i,j}=i*m+j+1$.现在可以交换矩阵的两列或者两行.在任意多次操作后使得矩阵对应的字符串最大? 思路:从1到$n*m$,依次枚举.每次将当前数字填回正确位置.比较该次操作前后是否变大.不变大则不做本次操作. #include <stdio.h> #include <vector> #include <