P1248 加工生產排程&P2123 皇后遊戲
Johnson 法則早就該會了……
一般地,設 \(c_i\) 表示完成第 \(i\) 個後的時間,得
\[c_i=\begin{cases} a_1+b_1 &(i=1)\\ \max\left(c_{i-1},\sum\limits_{j=1}^i a_j\right)+b_i &(i>1) \end{cases}\]在調整法之前,有一個顯然的結論:若 \(c_i\) 變小,其後的 \(c\) 都會變小。
之後考慮調整。令 \(T\) 表示前面數的 \(a\) 之和,\(P\) 表示 \(c_{i-1}\)
\(i\)
\(j\) 在前:\(\max(\max(P,T+a_j)+b_j,T+a_i+a_j)+b_i\)
等價於比較
\(\max\{T+a_i+b_i+b_j,T+a_i+a_j+b_j\}\)
\(\max\{T+a_j+b_i+b_j,T+a_i+a_j+b_i\}\)
兩式同減 \(T+a_i+a_j+b_i+b_j\) 得 \(\max(-a_j,-b_i)\) 與 \(\max(-a_i,b_j)\),即 \(-\min(a_j,b_i)\) 和 \(-\min(a_i,b_j)\)
分析可知當 \(\min(a_i,b_j)\leq \min(a_j,b_i)\)
照著上述思路,可以寫出一份能 AC P1248 的程式碼。
#include <cstdio> #include <cctype> #include <algorithm> using namespace std; char buf[1<<14],*p1=buf,*p2=buf; #define GetC() ((p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++) struct Ios{}io; template <typename _tp> Ios &operator >>(Ios &in,_tp &x){ x=0;int w=0;char c=GetC(); for(;!isdigit(c);w|=c=='-',c=GetC()); for(;isdigit(c);x=x*10+(c^'0'),c=GetC()); if(w) x=-x; return in; } const int N=1e5+5; struct qwq{int a,b,id;}a[N]; bool operator <(qwq x,qwq y){return min(x.a,y.b)<min(y.a,x.b);} int main(){ int n;io>>n; for(int i=1;i<=n;++i) io>>a[i].a; for(int i=1;i<=n;++i) io>>a[i].b,a[i].id=i; sort(a+1,a+n+1); long long s1=a[1].a,s2=a[1].a+a[1].b; for(int i=2;i<=n;++i){ s1+=a[i].a; s2=max(s2,s1)+a[i].b; } printf("%lld\n",s2); for(int i=1;i<=n;++i) printf("%d%c",a[i].id," \n"[i==n]); return 0; }
這麼做過不了P2123。
接下來的內容來自 @ouuan 淺談鄰項交換排序的應用以及需要注意的問題 一文。
hack 資料見此:
2
4
1 1
1 1
3 5
2 7
4
1 1
3 5
1 1
2 7
原因在於兩次排序結果分別為
1 1
1 1
2 7
3 5
和
1 1
3 5
1 1
2 7
接下引入嚴格弱序這一概念。
對於一個比較運算子(用“\(<\)”表示此運算子,用“\(\not <\)”表示不滿足此運算子),若滿足以下四個條件,則稱其是滿足嚴格弱序的:
- \(x\not< x\)(非自反性)
- 若 \(x<y\) ,則 \(y\not <x\)(非對稱性)
- 若 \(x<y,y<z\),則 \(x<z\)(傳遞性)
- 若 \(x\not<y,y\not<x,y\not < z,z\not<y\),則 \(x\not <z,z\not <x\)(不可比性的傳遞性)
可以證明,我們定義的 “\(<\)” 運算具有傳遞性,但不具有不可比性的傳遞性。
換句話說,可能會出現較大的數出現在前面的情況。然後就不是最優了。
所以,必須保證具有不可比性的傳遞性。
對 \(\min(a_i,b_j)<\min(a_j,b_i)\) 進行大力分討,可得到以下方法:
定義 \(d_i=\begin{cases}-1 & a_i<b_i\\0 &a_i=b_i\\ 1&a_i>b_i\\\end{cases}\)
先按 \(d\) 排。對於 \(d_i=-1\) 的元素,可以按照 \(a\) 從小往大排,對於等於 \(0\) 的元素,隨便排,對於 \(d_i=1\) 的元素,按照 \(b\) 從大往小排。
這玩意就叫 Johnson 法則。