@
コンセプト
近傍交換ソーティングは一般的な貪欲なアルゴリズムであり、シーケンス全体に対して隣接する2つの要素を決定する決定を一般化して、最適なソリューションを取得します。
Ⅰ:P1080キングゲーム
タイトルリンク
タイトルの説明
Hの建国記念日と同じ時期に、王はn人の大臣を賞品ゲームに招待しました。まず、彼は各大臣に左手と右手に整数を書くように頼み、王自身も左手と右手に整数を書いた。次に、n人の大臣が列をなすようにし、王が列の前に立ちます。並んだ後、すべての大臣は国王から報酬が与えられる多数の金貨を受け取ります。各大臣が受け取る金貨の数は、大臣の前にいる全員の左手にある数を自分の右手にある数で割った積です。次に、結果を切り捨てます。
王様は、特定の大臣が特に多くの報酬を受け取ることを望んでいないため、最も多くの報酬を受け取る大臣ができる限り少ない報酬を受け取るように、チームの順序を再調整するのを手伝ってほしいと願っています。王の位置は常にチームの前にあることに注意してください。
入力フォーマット:
最初の行には、大臣の数を表す整数nが含まれています。
2行目には、スペースで区切られた2つの整数aとbが含まれ、キングの左手と右手にある整数を表します。
次のn行では、各行にスペースで区切られた2つの整数aとbが含まれ、各大臣の左手と右手の整数を表します。
出力フォーマット:
再編成されたチームで最も多くの賞を受賞した大臣が受け取った金貨の数を表す整数。
入力サンプル#1:
3
1 1
2 3
7 4
4 6
出力サンプル#1:
2
【データ範囲】
データの20%の場合、1≤n≤10,0 <a、b <81≤n≤10,0<a、b <8;
データの40%の場合、1≤n≤20,0<a、b <81≤n≤20,0<a、b <8;
データの60%の場合、1≤n≤1001≤n≤100;
データの60%について、回答が10 ^ 9109を超えないようにしてください。
100%データの場合、1≤n≤1,000,0<a、b <100001≤n≤1,000,0<a、b <10000があります。
思考が
提供さIおよびjは両方の左大臣の前で提供されるすべての数の積に、隣接する二つの大臣されているK、その後、
①もし私のJ報酬の前の値が大きいほど、両方の大臣
②場合は、私がでjはバック、2つの値が大きい報わ大臣であります
問題の意味最小要件の最大値は、我々が設定されているので、私の中でjを満たすために、この時のニーズに、より良いフロントを
もう一度
次に、上記の式は
次に、この式(決定)をシーケンス全体に一般化します。つまり、この優先順位に従って、最終的な解が最適な解でなければなりません。
される理由のいくつかは、疑問に思うことがあり、シーケンス全体に拡張しますか?iとjが隣接していない場合はどうなりますか?
シーケンス全体について、シーケンスのすべての近傍は上記の決定を満たす必要があります。これは、この決定に従ってソートすることと同じです。
それがわからない場合は、シミュレーションしてみましょう。上記のように、これら2つの要素の最適なソリューションを確実に実現するには、隣接する2つの要素が上記の式を満たす必要があることが証明されています。隣接しない要素iとj(jがiの後ろにあると想定)、2つの位置で要素を交換すると、それは満たされない
また、もう満足していません
そして
方程式(1)の場合:最初の行の不等式の要素が隣接している場合、最初の行が満たされるように要素を交換し、2番目の行の要素が隣接している場合は交換します。。iの元の要素がjの位置に到達するまで、iからjへの元の要素は1つ前に移動されます。このとき、近傍の交換順序は完全に(1)を満たし
、(2)についても同様です。方程式:最後の行の不等式の要素が隣接し、それらの要素を交換します。次に、最後から2番目の行の要素が隣接し、次に交換します... jの元の要素がiの位置に到達するまで交換し、隣接する交換を使用しますソートは式(2)を完全に満たします。
これから:シーケンス全体で、私たちの決定を満たさない近傍順序はありません。
:対象の上に近所の本質は、アイテムを交換しているようだ説明できる意思決定の導入 Aを見て、その後、
Ⅱ:P2123クイーンゲーム
トピックリンク
質問の意味、我々セット大臣Iおよびjの前の2人の閣僚のボーナスの大臣に隣接してはCであり、すべての閣僚が、その後、合計放置前の2人の閣僚の数
ならば① Iにおけるjはフロント、次に、2つの大臣のボーナスの大きい方の値は$$ max(max(C、sum + a_ {i})+ b_ {i}、sum + a_ {i} + a_ {j})+ b_ {j} 、これは$$
②場合iは、でjはバック、2つの大きな値大臣が報酬$$ MAX(MAX(C、和 + A_ {J})+ B_ {J}、和+ A_ {I} + A_ {J })+ b_ {i}、つまり$$
問題は、最大値が最小であるということです。私はiを前により良く設定し、
中の最大を分解する、すなわち
うち
排除し(後で排除できる理由については後で説明)、その後、
合計を消去
簡素化、取得
シフトアイテム
大きい数は左側と右側の両方で削除され、小さい数の反対が残ることに注意してください。
消去负号
最も単純な最終決定を見つけ、それをシーケンス全体に拡張して最適なソリューションを取得したようです。
なぜ同じ項を削除できるのか、上の式を簡略化して
\ [max(a1、b1、c)\ leqslant max(a2、b2、c)\]したがって、cがすべての数値の中で最大である場合、左側と右側は等しくなります。変更するかどうかにかかわらず、同じです
。cがすべての数値の中で最大でない場合、この不等式がtrueであると判断されるだけなので、cの存在については気にしません。 cより大きい要素。
だから、あなたはcを排除することができます
ただし、この決定は誤りです。そんなにと間違っている。しかし、不完全な優れた記述、
標準の説明は、この決定は満たしていないためということで厳しい弱い順序がある同等の推移ではありません。一連のデータで直接説明します
これは、どのような簡単な説明推移は比較できない、すなわち、\(<= B、B <= C \) ない放出することができる\(A <= \ C) 、この場合は、直接シーケンス全体に一般化することはできません満たすために何かを追加する必要が比較できない推移仕事を。
競合が\(min(b_ {i}、a_ {j})= min(b_ {j}、a_ {i})\)によって引き起こされていることがわかっているため、隣人を交換してあいまいにする必要があるかどうかを確認し、与えられた質問を分析しますこの式で
は、aのプレフィックスが回答に特定の影響を与えることがわかります。したがって、それらが等しい場合は、前に小さい値を配置することをお勧めします。同様に、bも回答に影響を与える必要があり、各bが計算されます一度、等しい場合は、その前にbを置くことをお勧めします。次に、2つのソリューション(つまり、2つの正しい決定)を引き出すことができます。
================================================== =========
#include<bits/stdc++.h>
using namespace std;
#define I inline
#define rg register
#define ll long long
I ll rd()
{
ll x=0,f=0; char c=getchar();
while(!isdigit(c)){f|=c=='-';c=getchar();}
while( isdigit(c)){x=(x<<3)+(x<<1)+(c-48);c=getchar();}
return f?-x:x;
}
const int N = 2E4+10;
struct node{
ll a,b;
bool operator < (const node& x)const{
return min(a,x.b)==min(x.a,b)?a<x.a:min(a,x.b)<min(x.a,b); //决策 1
return min(a,x.b)==min(x.a,b)?b>x.b:min(a,x.b)<min(x.a,b); //决策 2
}
}e[N];
int n;
int main()
{
int T=rd();
while(T--)
{
n=rd();
for(int i=1;i<=n;i++) e[i].a=rd(),e[i].b=rd();
sort(e+1,e+n+1);
ll sum=e[1].a+e[1].b,pre=e[1].a;
for(int i=2;i<=n;i++)
pre+=e[i].a,sum=max(sum,pre)+e[i].b;
printf("%lld\n",sum);
}
}
各グループについて\((a_ {i}、b_ {j})\) 2つの要素間の関係も答えに影響を与えるため、
ここで、すべての要素は、\(min(b_ {i}、a_ {j})\ leqslant min(b_ {j}、a_ {i})\)に従って、3つのカテゴリに分類されて判断されます:
\(①d_ {i} = d_ {j} = -1、aの昇順で配置; \)
\(②d_ {i} = d_ {j} = 0、ランダムに配置; \)
\(③d_ {i} = d_ {j} = 1、bの降順; \)
残りの\(d_ {i}!= D_ {j} \)は、\(d_ {i} <d_ {j} \)が満たされる限り満たすことができます\(min(b_ {j}、a_ {i})\ leqslant min(b_ {i}、a_ {j})\)要約すると、新しい決定は古い決定の制約を完全に満たすだけでなく、比較できないの送信(見つけるのは困難ではない、要素の分類の後に、各タイプの要素間の転送を有し、また、クラス間の移動抵抗を有する)が、この方法は、第三の溶液を得ました。
================================================== =========
#include<bits/stdc++.h>
using namespace std;
#define I inline
#define rg register
#define ll long long
I ll rd()
{
ll x=0,f=0; char c=getchar();
while(!isdigit(c)){f|=c=='-';c=getchar();}
while( isdigit(c)){x=(x<<3)+(x<<1)+(c-48);c=getchar();}
return f?-x:x;
}
const int N = 2E4+10;
struct node{
ll a,b,d;
bool operator < (const node& x)const{
if(d==x.d)
{
if(d<=0) return a<x.a;
else return b>x.b;
}
return d<x.d;
}
}e[N];
int n;
int main()
{
int T=rd();
while(T--)
{
n=rd();
for(int i=1;i<=n;i++){
e[i].a=rd(),e[i].b=rd();
if(e[i].a<e[i].b) e[i].d=-1;
if(e[i].a==e[i].b) e[i].d=0;
if(e[i].a>e[i].b) e[i].d=1;
}
sort(e+1,e+n+1);
ll sum=e[1].a+e[1].b,pre=e[1].a;
for(int i=2;i<=n;i++)
pre+=e[i].a,sum=max(sum,pre)+e[i].b;
printf("%lld\n",sum);
}
}
Ⅲ:P1248生産計画の処理
分析:これは典型的なパイプラインスケジューリングの問題です。ネイバーエクスチェンジのアイデアでは、最初に2つの製品しかなく、処理時間は\((a_ {i}、b_ {i})と(a_ {j }、B_ {J})\) 、次いで
①場合、私はでj個のフロント、時間が必要である(a_iを+ MAX(a_j、B_i)+ b_j \)\ ;
②場合Iにおけるjの後、必要な時間である(\ a_j + max(a_i、b_j)+ b_i \) ;
ここで、前者の方が優れていると想定し、
シフトアイテム
左側と右側の両方は、小さな反対の数字を残すことと同等です。
最終的にマイナス記号を削除する
同様に、この決定は確かに満たしていない場合には比較できないの通過にそれらを繰り返さないで、問題として、その溶液を。
================================================== =========
#include<bits/stdc++.h>
using namespace std;
#define I inline
#define rg register
#define ll long long
I ll rd()
{
ll x=0,f=0; char c=getchar();
while(!isdigit(c)){f|=c=='-';c=getchar();}
while( isdigit(c)){x=(x<<3)+(x<<1)+(c-48);c=getchar();}
return f?-x:x;
}
const int N = 2E4+10;
struct node{
ll a,b,d,id;
bool operator < (const node& x)const{
if(d==x.d)
{
if(d<=0) return a<x.a;
else return b>x.b;
}
return d<x.d;
}
}e[N];
int n;
int main()
{
n=rd();
for(int i=1;i<=n;i++) e[i].a=rd();
for(int i=1;i<=n;i++) e[i].b=rd();
for(int i=1;i<=n;i++){
e[i].id=i;
if(e[i].a<e[i].b) e[i].d=-1;
if(e[i].a==e[i].b) e[i].d=0;
if(e[i].a>e[i].b) e[i].d=1;
}
sort(e+1,e+n+1);
ll sum=e[1].a;
for(int i=2;i<=n;i++)
if(e[i].a>=e[i-1].b) sum+=e[i].a;
else e[i+1].a-=(e[i-1].b-e[i].a),sum+=e[i-1].b;
sum+=e[n].b;
printf("%lld\n",sum);
for(int i=1;i<=n;i++) printf("%d%c",e[i].id,i==n?'\n':' ');
}