(L3-012)フルーツ忍者(思考+列挙)

トピックリンク:PTA|プログラム計画実験支援教育プラットフォーム

f

分析:この質問では、最初に質問の意味を満たす直線の特別な特性を見てみましょう。直線lがこれらのn線分を通過できる場合、およびlがいずれかの下端を通過しない場合線分を移動して、線分の下の端点を通過するまで下に移動できます。この時点では、下に移動を続けることはできませんが、端点を通過するまで通過した下の端点を中心に回転できます。つまり、解決策がある場合は、[別の解決策を検索]を作成して、2つの線分の端点を通過させることができます(上下の端点は関係ありません) 。これにより、次のような状況が解決されます。答えに必要な4つの座標はすべて整数解です。

それは正確にはどういう意味ですか?つまり、下の端点を通り、質問の意味を満たす直線があると仮定して、任意に線分を選択し、他の線分の端点に接続して、ターゲットの勾配範囲を取得します。直線、対象の直線が通る点はすでにわかっているので、この点と線分の2つの端点を接続して、2本の直線を形成します。これらの2本の直線は、それぞれ勾配に対応します。最後の直線のは2本の直線の傾きの間にあり、線分を通過できるので、いつでも目標線の傾きの範囲を狭めることができます。最終的な傾きの最大値がより大きい場合勾配の最小値は、質問の意味を満たし、最初に想定した線分の下端を通過する線があることを意味しますプロセスでターゲットラインの傾斜範囲を狭めているため、トラバースする現在のラインセグメントがターゲットラインの傾斜範囲を縮小すると、現在のラインセグメントの端点を通過するポイントとして使用できることを意味します。ターゲットライン。トラバーサルポイントと現在のトラバーサルラインセグメントによって形成される2つの直線の勾配範囲には、ターゲット直線の勾配範囲が含まれるため、ターゲット直線の勾配範囲には影響しません。プロセス中に更新ターゲット間隔のエンドポイントのみを記録する必要があります。はい、最後に、ターゲットラインの間隔の長さが正の場合は出力します。それ以外の場合は、次のラインセグメントの下部ブレークポイントを次の行セグメントまでトラバースし続けます。質問の意味を満たす行が見つかります。

コードは次のとおりです。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=1e4+10;
struct node{
	int x,y1,y2;
}p[N];
bool cmp(node a,node b)
{
	return a.x<b.x;
}
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		scanf("%d%d%d",&p[i].x,&p[i].y1,&p[i].y2);
	sort(p+1,p+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
		double kmin=-0x3f3f3f3f,kmax=0x3f3f3f3f;
		double tmin,tmax;
		int tx,ty;
		bool flag=true;
		for(int j=1;j<=n;j++)
		{
			if(p[i].x==p[j].x) continue;
			if(i>j)
			{
				tmax=(double)(p[i].y2-p[j].y2)/(p[i].x-p[j].x);
				tmin=(double)(p[i].y2-p[j].y1)/(p[i].x-p[j].x);
				if(tmax<kmax)//斜率最大值被更新,记录更新斜率最大值的端点 
				{
					kmax=tmax;//斜率最小值被更新,记录更新斜率最小值的端点
					tx=p[j].x;ty=p[j].y2;//记录临界点坐标 
				}
				if(tmin>kmin)
				{
					kmin=tmin;
					tx=p[j].x;ty=p[j].y1;//记录临界点坐标 
				}
			}
			else
			{
				tmax=(double)(p[j].y1-p[i].y2)/(p[j].x-p[i].x);
				tmin=(double)(p[j].y2-p[i].y2)/(p[j].x-p[i].x);
				if(tmax<kmax)//斜率最大值被更新,记录更新斜率最大值的端点
				{
					kmax=tmax;
					tx=p[j].x;ty=p[j].y1;//记录临界点坐标 
				}
				if(tmin>kmin)//斜率最小值被更新,记录更新斜率最小值的端点
				{
					kmin=tmin;
					tx=p[j].x;ty=p[j].y2;//记录临界点坐标 
				}
			}
			if(tmin>kmax||tmax<kmin||kmax<kmin)//出现无解,也就是说不存在过第i条直线的下端点的直线满足题意 
			{
				flag=false;
				break;
			}
		}
		if(flag)
		{
			printf("%d %d %d %d",p[i].x,p[i].y2,tx,ty);
			break;
		}
	}
	return 0;
}

おすすめ

転載: blog.csdn.net/AC__dream/article/details/123877235