题解:P2963 [USACO09NOV] Cow Rescue G
另类做法。
感谢 @chenly8128 提供的图片。
思路
首先我们对每个点坐标重新标号。即原来的
然后我们需要对于起点,画
这两条线把整个平面分成了
首先,在同一直线上的点
同一纵坐标的点也有性质:对于点
然后对于
关键是对于另外两个区域的求解,以区域
研究两条直线的性质,发现:从左下到右上的线途径的点横纵坐标之和只有两个值,这样我们就可以用
从左上到右下线上的点也满足一个性质:横纵坐标差为定值(此处的横纵坐标差默认为
手搓一下就会发现:
这样,我们可以
假如我们要求
首先要明确一个事实:如果
不难发现交点有
我们选取奇数的求解交点坐标
按照上面的性质:
为奇数, 为偶数, 为偶数, 为奇数。
可以发现
显然
然后就可以用直线上点的坐标公式求距离了。假设起点是
到这里我们就做完了。证明在代码下面。
注意一个细节:Bessie 逃出迷宫还要再花
另一个细节:我们在前面转化了横纵坐标,但是题目中要求输出的不是这个,所以要转回去。原来是
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,x[10005],y[10005],ansx,ansy,ans=2147483647,sx,sy,nans;
int abss(int _){
if(_>0)return _;
return -_;
}
int main(){
cin>>n>>m>>sx>>sy;
sy=n-sx+sy;
int a,b,c,d;
if((sx+sy)%2==1){
a=sx+sy;
b=a+1;
}
else{
b=sx+sy;
a=b-1;
}
for(int i=1;i<=m;i++){
cin>>x[i]>>y[i];
y[i]=n-x[i]+y[i];
}
for(int i=1;i<=m;i++){
int hc=abss(sx-x[i]),zc=abss(sy-y[i]);
if(hc<=zc){
nans=hc+zc;
}
else{
if((x[i]-y[i])%2==0){
c=y[i]-x[i];
d=c+1;
}
else{
d=y[i]-x[i];
c=d-1;
}
int jx,jy;
jx=(a-d)/2;
jy=a-jx;
nans=abss(jx-x[i])+abss(jx-sx)+abss(jy-y[i])+abss(jy-sy);
}
if(nans<ans){
ansx=x[i];
ansy=y[i];
ans=nans;
}
}
cout<<ansx<<' '<<(ansy-n+ansx)<<endl<<ans+1;
return 0;
}
证明
如何证明上面的做法是正确的?
其实我们可以把这个三角形矩阵抽象成一个正方形矩阵:
黑色代表可以走,红色则代表不能走。
不难发现我们在原图中画的每一条线(即两条蓝线和一条绿线)都是正好绕过了每一个不能走的边。
首先对于区域
再加上同一纵坐标上的移动,这一条线实质上是绕着长方形边框走了一圈,显然最优。
再看线内:
我们显然希望绕过的红边最少最优,因为每绕过一个红边就要多走两步。
而我们在前面提到我们在原图中画的每一条线(即两条蓝线和一条绿线)都是正好绕过了每一个不能走的边,也就是意味着它走了每一条可以走的边。
或者可以这么理解:我们如果沿着绿线从
所以这样的路线一定是最优的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】