1. 程式人生 > 其它 >洛谷 P7885 「MCOI-06」Flight題解

洛谷 P7885 「MCOI-06」Flight題解

題目連結

這是一道隱藏的很深的結論題好像只是因為我太弱,我一開始看時以為是個模擬,然後看到資料範圍之後我傻了。
怎麼辦呢?我們要堅信暴力出奇跡,打表出省一畫圖可以解決一切問題。

於是這個圖就出來了

然後根據玄學手推可以推出最短路是這個樣子的

由此我們可以得到一種情況,也就是當a=b且c=d時兩點間的最短路為兩點的曼哈頓距離,公式為$|x_1-x_2|+|y_1-y_2|$。敲黑板!曼哈頓距離是本題解題的關鍵

但是毒瘤大犇出題人怎麼可能這麼輕易地就放過我們呢。

於是我們可以通過第一種情況延伸出剩下兩種情況

abcd形成一個長方形的

a=c的(Subtask2)

這裡就會有人問了,誒誒你不是說從第一個延伸出來的嗎,怎麼看著跟第一個一點關係都沒有呢?不要著急,等我把這兩種情況的最短路畫出來你就知道了

第二種情況

第三種情況

我們可以把第二種情況看做先把cd所在的那一行當成正方形的底,然後走一遍情況一,再直走走到點cd

直走我們用的方法是這個樣子的,因為題目要求不能連續往同一個方向走,而這樣走可以被證明每一步是最短的

按這樣直走,我們可以算出直走所需要的的步數,但是這裡需要分類討論(此處為本題巨坑,本蒟蒻卡在這裡調了兩個多小時),一種是兩點的距離為偶數,一種是兩點的距離是奇數。

兩點的距離是偶數時,步數為兩點的距離乘以二,因為每走一步之後需要重置方向,要往上或往下再走一步。

兩點的距離是奇數時,步數為兩點的距離乘以二減一,因為走最後一步時不需要再重置方向了,所以要減去多的一步(斜線劃分步數)

因為當我們從點ab走到正方形的右下角時,正方形的右下角和點cd在一條橫軸上,所以我們直接走直線即可到達點cd,所需的步數即為從點ab走到正方形右下角的步數加從正方形右下角走直線到點cd的步數。

而情況三則比較簡單,直接從點ab走直線到點cd即可。

本題最大的難點在於分類討論和三種情況的解決,都解決後其實就是一道結論題

AC程式碼

#include<iostream>
#include<cstdio>
#include<cmath>
#define int long long//反正空間夠,不開long long見祖宗,而且你必須開
using namespace std;
signed main()//因為define了int,所以要改成signed
{
	int T;
	cin>>T;
	for(int cishu=0;cishu<T;++cishu){
		int a,b,c,d;
		cin>>a>>b>>c>>d;
		int ac=abs(a-c),bd=abs(b-d);
		int temp=ac,ans=min(ac,bd);
       //哪邊小把哪邊當做正方形的底,要不然就把點cd越過去了
		ac-=min(temp,bd);//求需要直走的長度
      bd-=min(temp,bd);
		int bigger=max(ac,bd);
		if(bigger&1) cout<<(ans*2+bigger*2-1);
      //位運算判斷奇偶更快
		else cout<<(ans*2+bigger*2);
		cout<<endl;
	}
	return 0;
}