Cut the Cake!题解

题目描述

On the faraway planet of Gastronomia, the native Gastronomes consider polygonal pancakes to be the highest form of art (as well as the tastiest). Every year, they celebrate the Polycake Festival, in which thousands of ninja chef monasteries perform the Thousand Slices, a series of rituals of tremendous importance to Gastronome society. In each of these rituals, a polycake is carefully placed on a ceremonial altar, and a ninja chef will solemnly cut the cake with a single, perfectly straight slice, dividing it into two pieces, one on the North part of the altar (representing the past) and the other on the South part (representing the future). The two pieces are carefully separated, and their perimeters measured. The results will determine the proportions of the ingredients used in polycakes planetwide, until the next Polycake Festival.

As the foremost Novice at the Temple of the Promised Cosmic Polycake, you are entrusted the task of measuring the perimeters of the two slices. Take care, for any mistakes will be mercilessly mocked by the Brotherhood of the Illusory Polycake1. It would be best if you wrote a program to do this.

The Problem:

Given a polygon representing the polycake in the Cartesian plane and a line parallel to the X-axis indicating the position of the slice, you are to compute the perimeter of each of the two pieces thus formed. The perimeter of a polygon is defined as the sum of the lengths of all its sides. Assume that the input polygons will be convex (i.e., not concave) and simple (i.e., not complex, not intersecting).

输入描述

The first input line contains a positive integer, nn, indicating the number of polycakes used in the ritual. This is followed by nn data sets, each representing a single slicing of a polycake.

The first line of each set consists of two integers, VV (3≤V≤103≤V≤10) and YY (−1000≤Y≤1000−1000≤Y≤1000), representing the number of vertices in the polycake and the yy-coordinate of the horizontal cut, respectively. (Recall that the equation of a line parallel to the X-axis is of the form y=ky=k.)

The next VV lines each contain two integers, xx and yy (−1000≤x,y≤1000−1000≤x,y≤1000), the Cartesian coordinates of the vertices of the polycake, in counter-clockwise order.

To minimize complications (and following the rules of the ritual), it is guaranteed that the cut will always go through the cake and will never pass through a vertex.

输出描述

For each test case, output one line. That line should contain “a ba b”, the perimeters of the two slices, in increasing order. Output the results to 3 decimal places, rounded to the nearest thousandth (e.g., 77.0113 should round to 77.011, 88.0115 should round to 88.012, and 99.0117 should round to 99.012).

样例

输入 

2
4 2
0 0
4 0
4 4
0 4
6 10
3 15
10 1
12 5
11 19
9 23
6 20

输出 

12.000 12.000
25.690 35.302

题目大意:

给你一个多边形(多边形顶点以坐标形式给出),然后用一条平行于x轴的直线截成上下两部分,然后求上下两部分的周长,输出周长的时候小的在前。

思路:

        输入:给的都是点嘛,所以就用pair<int,int>预存,然后存到相应类型的vector容器里面,然后中间要是遇到了多边形的两点连线与直线相交要做一个处理……

这里有两种情况:

(直线AB是多边形的一条边,本情况中AB恰好是是与直线Y=y相交的多边形的边,不与直线Y=y相交的边都不考虑,只需要存好点就行了)

情况一:

情况二:

 然后就是求C点(x,y)中,y 已经知道了;

可以用斜率相等求

(x1-x2)/(y1-y2)=(x-x1)/(y-y1);

也就是

 x = (x1 * (y - y2) + x2 * (y1 - y)) / (y1 - y2);

然后将求得的x,连同y作为点存入vector容器中

然后输入就结束了;

之后就是求值了;

怎么求呢?

原本这样的多边形

切开以后张这样

很容易发现在直线Y=y上面的点与点连线的长都加起来

Y=y下面的点与点的连线的长都加起来

因为在存点的时候按逆时针方向存的,然后那分割线的两点也是在出现两点连线与分割线相交的那个时机存的,所以分割线两点加以限制条件是可以变成相邻的,比如只看上面,或只看下面,具体方法见代码。

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
vector<pair<double, double> >vc;
int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		int n, y;
		vc.clear();
		pair<double, double> temp;
		double xx, yy, sum1 = 0, sum2 = 0;
		scanf("%d%d", &n, &y);
		for (int i = 0; i < n; i++)
		{
			scanf("%lf%lf", &xx, &yy);
			if (i)//从第二点开始
			{
				double x2 = xx, x1 = temp.first, y2 = yy, y1 = temp.second;
				if ((y >= temp.second && y <= yy) || (y <= temp.second && y >= yy))//两种情况
				{
					double x = (x1 * (y - y2) + x2 * (y1 - y)) / (y1 - y2);//求与线相交的x坐标
					vc.push_back(make_pair(x, y));
					/*	cout << "temp" << "(" << temp.first << "," << temp.second << ")" << endl;调试用的
						cout << "(" << x << "," << y << ")" << endl;*/
				}
			}
			temp.first = xx; temp.second = yy;//把当前点的(x,y)暂时存起来
			vc.push_back(temp);//把点存到容器里面
		}
		pair<double, double>node = *vc.begin(), st;
		double x2 = node.first, x1 = temp.first, y2 = node.second, y1 = temp.second;//最后一个点与第一个点连线是否与Y=y相交
		if ((node.second >= y && temp.second <= y) || (node.second <= y && temp.second >= y))//两种情况
		{
			double x = (x1 * (y - y2) + x2 * (y1 - y)) / (y1 - y2);
			vc.push_back(make_pair(x, y));
			/*cout << "temp" << "(" << temp.first << "," << temp.second << ")" << endl;
			cout << "(" << x << "," << y << ")" << endl;*/
		}
		int cnt = 0;
		
		for (auto it : vc)
		{
			if (it.second <= y)//Y=y 下面
			{
				/*cout << it.first << " " << it.second << "&&&" << endl;*/
				if (cnt++)//从满足条件的第二个点开始
					sum1 += sqrt((it.second - node.second) * (it.second - node.second) + (it.first - node.first) * (it.first - node.first));//两点间距离公式
				else
					st = it;//储存第一个点,方便算和最后那个点之间的距离
				node = it;//暂时存上一个点,之后要用
			}

		}
		sum1 += sqrt((st.second - node.second) * (st.second - node.second) + (st.first - node.first) * (st.first - node.first));//最后一个点与第一个点之间的距离

		cnt = 0;

		for (auto it : vc)
		{
			if (it.second >= y)//Y=y上面
			{
				if (cnt++)
					sum2 += sqrt((it.second - node.second) * (it.second - node.second) + (it.first - node.first) * (it.first - node.first));
				else
				{
					st = it;
				}
				node = it;
			}
		}
		sum2 += sqrt((st.second - node.second) * (st.second - node.second) + (st.first - node.first) * (st.first - node.first));
		if (sum1 > sum2)//小的在前
			swap(sum1, sum2);
		printf("%.3lf %.3lf\n", sum1, sum2);
	}
	return 0;
}

注意:最后如果思路觉得很对,但是WA了,要回去再看看原题,即使那个题面很长~~~,可能有意外的收获……

END

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值