1. 程式人生 > 其它 >P1248 加工生產排程&P2123 皇后遊戲

P1248 加工生產排程&P2123 皇后遊戲

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\)

在前:\(\max(\max(P,T+a_i)+b_i,T+a_i+a_j)+b_j\)
\(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)\)

\(i\)\(j\) 前面更優。

照著上述思路,可以寫出一份能 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 <\)”表示不滿足此運算子),若滿足以下四個條件,則稱其是滿足嚴格弱序的:

  1. \(x\not< x\)(非自反性)
  2. \(x<y\) ,則 \(y\not <x\)(非對稱性)
  3. \(x<y,y<z\),則 \(x<z\)(傳遞性)
  4. \(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 法則。