1. 程式人生 > 實用技巧 >題解 P3076 【[USACO13FEB]Taxi G】

題解 P3076 【[USACO13FEB]Taxi G】

昨天 \(\texttt{zwj}\) 老師 在 \(\texttt{貪心}\) 專題講了這道題,特此水一篇題解。

(其實是因為一個多月沒寫題解了,感覺社群分會掉下70)

先以樣例為例子來看看:

(但為了突出其某些性質,把 \(s1\) 改為了 \(2\),但其答案不變)

\(\texttt{Bessie}\)\(0\) 號站到 \(2\) 號站接第 \(1\) 個客戶(\(2\) 站),從 \(2\) 號站出發到 \(6\) 號站(\(4\) 站),放下第 \(1\)個客戶,接第 \(2\) 個客戶,送到 \(5\) 號站再回來(\(2\) 站),再接第 \(1\) 個客戶,送到 \(9\)

號點(\(3\) 站),然後自己走到 \(10\) 號點(\(1\) 站),共 \(12\) 站。

那麼畫出圖來是這樣的(\(p_1->p_8\)):

我們不難發現,\(\texttt{Bessie}\) 走的路程,即 \(ans\),必然滿足 \(ans \ge \sum\limits_{i=1}^n |s_i-t_i|\)

那麼,思考一下,\(ans\)\(\sum\limits_{i=1}^n |s_i-t_i|\) 多出來了什麼呢?/yiw

來畫個圖吧~

如圖,紅線即為多出的部分,可能你還是看不出什麼。那麼我們把 \(\texttt{Bessie}\) 看成一隻從 \(M\)

走到 \(0\) 的牛,即 \(s_0->t_0\)

可以發現,紅線都是一條 \(s_i\)\(t_j\) 的線,且每個 \(s\)\(t\) 都被包含了,所以 \(ans=\sum\limits_{i=1}^n |s_i-t_i|+\sum |s_i-t_j|\)。又因為 \(\sum\limits_{i=1}^n |s_i-t_i|\) 是定值,我們的任務就是最小化 \(\sum |s_i-t_j|\)

然後把 \(s\)\(t\) 排序即可。設 \(s,t\) 排序後分別為 \(a,b\) ,則 \(ans=\sum\limits_{i=1}^n |s_i-t_i|+\sum\limits_{i=0}^n |a_i-b_i|\)

(別忘了 \(\texttt{Bessie}\) 的路程)。

那麼為什麼排序相減就最小呢?因為任意交換同陣列兩個數必然會使結果增大

\(\texttt{Ugly Code:}\)

#include<bits/stdc++.h>
using namespace std;
#define i64 long long//不開ll見祖宗
namespace io{static streambuf *inbuf=cin.rdbuf();static streambuf *outbuf=cout.rdbuf();char buf[1<<21],*p1=buf,*p2=buf;inline char gc(){return (p1==p2&&(p2=(p1=buf)+inbuf->sgetn(buf,1<<21),p1==p2)?EOF:*p1++);}inline void pc(const char x){static streambuf *outbuf=cout.rdbuf();outbuf->sputc(x);}inline void ps(const char *x){unsigned _len=strlen(x);for(unsigned i=0;i<_len;i++)pc(x[i]);}inline i64 read(){register int _s=0,_f=1;register char _ch=gc();for(;!isdigit(_ch);_ch=gc())if(_ch=='-')_f=-1;for(;isdigit(_ch);_ch=gc())_s=_s*10ll+_ch-'0';return _s*_f;}template<typename T>inline void write(T _x1){if(_x1<0)pc('-'),_x1=-_x1;static char _sta[15];int _p=0;do{_sta[_p++]=_x1%10^48;_x1/=10;}while(_x1);while(_p--)pc(_sta[_p]);}string _s;inline string readstr(){_s.clear();register char _ch=gc();while(isspace(_ch))_ch=gc();for(;!isspace(_ch);_ch=gc())_s+=_ch;return _s;}inline void writestr(const string _s){for(unsigned i=0;i<_s.size();++i)pc(_s[i]);}template<typename T>inline void writeln(const T _x){write(_x);pc(10);}}using namespace io;
//IO優化
const int maxn=1e5+5;
int n,m;
i64 ans,s[maxn],t[maxn];
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)
	{
		s[i]=read();t[i]=read();
		ans+=abs(s[i]-t[i]);//Σ|si-ti|
	}
	s[0]=m;t[0]=0;//Bessie的路程
	sort(s,s+n+1);sort(t,t+n+1);//排序啦
	for(int i=0;i<=n;i++)
		ans+=abs(s[i]-t[i]);//min(Σ|si-tj|)
	writeln(ans);
	return 0;
}