PAT L3-005. 垃圾箱分布 26分 测试点4 过不了

题目描述

大家倒垃圾的时候,都希望垃圾箱距离自己比较近,但是谁都不愿意守着垃圾箱住。所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方,同时还要保证每个居民点都在距离它一个不太远的范围内。

现给定一个居民区的地图,以及若干垃圾箱的候选地点,请你推荐最合适的地点。如果解不唯一,则输出到所有居民点的平均距离最短的那个解。如果这样的解还是不唯一,则输出编号最小的地点。

输入格式

输入第一行给出4个正整数:N(≤10^3​​ )是居民点的个数;M(≤10)是垃圾箱候选地点的个数;K(≤10^4​​ )是居民点和垃圾箱候选地点之间的道路的条数;D​S​​ 是居民点与垃圾箱之间不能超过的最大距离。所有的居民点从1到N编号,所有的垃圾箱候选地点从G1到GM编号。

随后K行,每行按下列格式描述一条道路:

P1 P2 Dist
其中P1和P2是道路两端点的编号,端点可以是居民点,也可以是垃圾箱候选点。Dist是道路的长度,是一个正整数。

输出格式

首先在第一行输出最佳候选地点的编号。然后在第二行输出该地点到所有居民点的最小距离和平均距离。数字间以空格分隔,保留小数点后1位。如果解不存在,则输出No Solution。

输入样例1
4 3 11 5
1 2 2
1 4 2
1 G1 4
1 G2 3
2 3 2
2 G2 1
3 4 2
3 G3 2
4 G1 3
G2 G1 1
G3 G2 2
输出样例1
G1
2.0 3.3
输入样例2
2 1 2 10
1 G1 9
2 G1 20
输出样例2
No Solution

测试点4过不了,难受……
26.jpg

C++ 代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+20;
int g[N][N];
int n,m,k,Ds,dis[N];
bool st[N];
int ans=-1;
double minD=-1,minavg;
void bfs(int start)
{
	memset(st,0,sizeof st);
	memset(dis,0x3f,sizeof dis);
	dis[start]=0;
	queue<int> q;
	q.push(start);
	st[start]=true;
	while(q.size())
	{
		auto t = q.front();
		q.pop();
		for(int i=1;i<=n+m;i++)
		{
			dis[i]=min(dis[i],dis[t]+g[t][i]);
			if(!st[i] && g[t][i]<0x3f3f3f3f/2)
			{
				q.push(i);
				st[i]=true;
			}	
		}
	}
	double mind=0x3f3f3f3f,avg=0;
	for(int i=1;i<=n;i++)
	{
		if(dis[i]>Ds) return ;
		avg+=(double)dis[i];
		if(mind>dis[i]) mind=dis[i];
	}
	avg=(double)((avg+0.05)/double(n));  //保留一位小数,+0.05
	mind=(double)(mind+0.05);
	if(mind > minD)
	{
		ans = start-n;
		minD = mind;
		minavg = avg;
	}
	else if(mind == minD && avg < minavg)
	{
		ans = start-n;
		minavg = avg;
	}
}
int main()
{
	memset(g,0x3f,sizeof(g));
	cin>>n>>m>>k>>Ds;
	string a,b;
	int d;
	for(int i=0;i<k;i++)
	{
		int a1,b1;
		cin>>a>>b>>d;
		if(a[0]=='G')
		{
			a=a.substr(1);
			a1=stoi(a)+n;	
		}
		else a1=stoi(a);
		if(b[0]=='G')
		{
			b=b.substr(1);
			b1=stoi(b)+n;	
		}
		else b1=stoi(b);
		//cout<<a1<<" "<<b1<<endl;
		g[a1][b1]=g[b1][a1]=d;
	}
	for(int i=n+1;i<=n+m;i++)
	{
		bfs(i);
	}
	if(ans==-1) puts("No Solution");
	else{
		cout<<"G"<<ans<<endl;
		printf("%.1f %.1f",minD,minavg);
	}
	return 0;
}
### 关于 PAT 天梯赛 L3-006 迎风一刀斩 测试点 3 和 5 的析 #### 测试点 3 的可能问题与解决方案 测试点 3 可能涉及输入数据中存在特殊几何形状的情况。例如,可能存在某些边界条件未被充考虑的情形。根据已有信息[^3],可以推测该测试点可能会考察以下几种特殊情况: 1. **三角形的直角判定**:如果程序未能正确处理浮点数精度误差,则可能导致直角检测失败。因此,在计算角度时应采用更精确的方法来比较两个向量之间的夹角是否接近 \(90^\circ\)。 2. **五边形的角度约束**:需确保五边形中有恰好三个直角,并且不存在小于 \(90^\circ\) 的锐角。这一步可以通过遍历所有顶点并逐一验证其相邻两条边所形成的夹角实现。 3. **删除边的数量校验**:依据参考资料[^4]提到的内容,“切的一刀笔直”,意味着原始多边形经过切割后仅允许保留两条有效边作为最终结果的一部。若实际操作过程中忽略了这一限制条件,则容易引发逻辑错误。 针对上述潜在风险点,建议如下改进措施: ```cpp // 判断两点间距离函数 double distance(const Point& p1, const Point& p2){ return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); } bool isRightAngle(double angle){ // 考虑到数值稳定性加入一定容忍范围 constexpr double EPSILON = 1e-8; return abs(angle-M_PI/2)<EPSILON || abs(angle+M_PI/2)<EPSILON; } ``` --- #### 测试点 5 的可能问题与解决方案 对于测试点 5 来说,通常会更加注重算法效率以及复杂场景下的鲁棒性表现。以下是几个常见的陷阱及其应对策略: 1. **时间性能瓶颈**:当面对大规模数据集时(比如上千甚至上万个坐标点),暴力枚举方法显然无法满足实时响应需求。此时应当引入高效的剪枝技术或者利用空间索引来加速查找过程。例如KD树能够显著降低高维查询耗时。 2. **异常情况遗漏**:除了标准矩形外还可能出现其他变形形态(如平行四边形)。这些情形下简单依赖固定规则匹配往往难以奏效,而应该动态调整参数阈值直至覆盖全部合法模式为止。 具体优化方向如下所示: ```cpp struct Rectangle{ vector<Point> vertices; bool isValid()const{ // 综合检验各项属性合法性 int count=0; for(int i=0;i<vertices.size();i++){ auto v1=getVector(vertices[i],vertices[(i+1)%vertices.size()]); auto v2=getVector(vertices[(i+1)%vertices.size()],vertices[(i+2)%vertices.size()]); if(isPerpendicular(v1,v2)) ++count; } return count==4 && !hasAcuteAngle(); } private: static Vector getVector(Point from,Point to); static bool isPerpendicular(Vector a,Vector b); bool hasAcuteAngle()const; }; ``` 通过以上方式可以在很大程度上提高代码健壮性和适应能力从而顺利通关相应挑战项目。 ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jay_fearless

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值