演算法競賽入門經典 訓練指南 筆記

2021-08-03 23:11:58 字數 3090 閱讀 6937

p1(貪心)

自己想的糟糕的演算法:

#include//從大到小排序龍頭和騎士,每個龍頭由「恰好」能砍掉的騎士來砍

#include//貌似沒問題,但是又難寫又慢

#include//就當複習stl了

#includeusing namespace std;

int n=1,m=1;

int a[30000];

vectorb;

vector::iterator iter;

bool boo[30000];

int b1;

bool cmp(int x,int y)

int main()

flag=false;

ans=0;

sort(a,a+n,cmp);

sort(b.begin(),b.end());

for(i=0;i

#include//從小到大排序龍頭和騎士,每個騎士砍對應龍頭,如果砍不了就換成下乙個,直到能砍了或騎士用完了為止

#includeusing namespace std;

const int maxn=20005;

int a[maxn],b[maxn];

int main()

if(cur

首先是直覺給出演算法:

猜想1:

執行時間長的先交代。

猜想2:

交代時間長的先交代。

然後是證明與完善:

考慮有相鄰執行的兩個任務x和y,現在要確定它們的順序,顯然它們的順序不會影響其它任務的完成時間。

①當它們執行時間一樣長時,不論交代時間關係如何,顯然順序並不影響完成時間。

由此,猜想2被否決。

並且,對於猜想1得到了完善:執行時間一樣長時先後順序任意。

②當它們執行時間不一樣長時:不妨設交換前先交代x。

a.交換前x比y後結束。

顯然,無論交代時間關係如何,交換它們只能讓完成時間更長。

b.交換前x比y先結束。

顯然,交換前總時間是x交+y交+y執,交換後是y交+max(y執,x交+x執)

那麼何時交換後能使時間變短呢?(如果說交換後時間變短,也就是說交換後的順序更好)

情況1:y執行那麼,交換後是y交+x交+x執

如果使時間變短,則x交+y交+y執》y交+x交+x執,即(x交+y交+y執)-(y交+x交+x執)>0,所以y執》x執

情況2:y執》=x交+x執

那麼,交換前總時間是x交+y交+y執,交換後是y交+y執,顯然時間變短,而此時顯然y執》x執

綜上所述,如果y執行時間更長,就應交換x和y的順序,使y先執行,也就是執行時間長的應該先執行。

(只列出x交代時間較長的情況,x交代時間較短也是類似的)

p4首先,舉個例子,1號給了2號1個金幣,2號給了1號3個,可以簡化為2號給1號2個金幣。

因此,把兩個人間金幣的交換簡化為單方向的給金幣。

xi表示第i個人給了第i-1個人xi個金幣(2<=i<=n) (x1表示第1個人給了第n個人x1個金幣)(如果xi為負則表示第i-1個人給了第i個人-xi個金幣)。

ai表示第i個人原有金幣。m表示每個人最後應有的金幣。

可以列出方程m=a1-x1+x2=a2-x2+x3=a3-x3+x4=...

則對於式1,x2=m-a1+x1

對於式2,m=a2-m+a1-x1+x3,x3=2m-a1-a2+x1=(m-a1)+(m-a2)+x1

對於式3,m=a3-2m+a1+a2-x1+x4,x4=3m-a1-a2-a3+x1=(m-a1)+(m-a2)+(m-a3)+x1

定義ci=(a1+a2+...+ai)-i*m

則x2=x1-c1

x3=x1-c2

x4=x1-c3

xn=x1-c(n-1)

現在,我們要求|x1|+|x2|+...+|xn|的最小值

就是|x1|+|x1-c1|+|x1-c2|+...+|xn-c(n-1)|的最小值

而c1到c(n-1)的值都是已經確定的,因此現在就是在數軸上找乙個點到0,c1,c2,...,c(n-1)的距離之和最小

可以證明,當這個點對應的數是0,c1,c2,...,c(n-1)的中位數時距離之和最小。

怎麼證明

//快速選擇,中位數bfprt

// #include#include#includeusing namespace std;

typedef long long ll;

ll c[1000100];

ll n,sum,m,ans;

//ll abs(ll a)

//int main()

m=c[n]/n;

for(i=1;i<=n;i++)

c[i]-=i*m;

sort(c,c+n);//不要寫成sort(c+1,c+n+1);,這樣會出bug

//最後要求的是|b1|+|b1-c1|+|b1-c2|+...+|b1-c(n-1)|的最小值,不涉及到cn

//可以令c0=0,那麼式子變為|b1-c0|+|b1-c1|+|b1-c2|+...+|b1-c(n-1)|

//這樣就可以變為求c[0]到c[n-1]的中位數

//因此,可以排序c[0]到c[n-1],然後取c[n/2]

b1=c[n/2];//舉例:0,1,2則為1;0,1,2,3則為1或2

// ans=abs(b1);

// for(i=2;i<=n;i++)

// ans+=abs(b1-c[i-1]);//錯在此時陣列c已經排完序,c[0]不再為0,只能按|b1-c0|+|b1-c1|+|b1-c2|+...+|b1-c(n-1)|來求

ans=0;//曾經因為前面的錯誤,忘記加上初始化

for(i=0;i

演算法競賽入門經典 訓練指南 筆記

p1 貪心 自己想的糟糕的演算法 include 從大到小排序龍頭和騎士,每個龍頭由 恰好 能砍掉的騎士來砍 include 貌似沒問題,但是又難寫又慢 include 就當複習stl了 includeusing namespace std int n 1,m 1 int a 30000 vecto...

演算法競賽入門經典訓練指南 4 1學習筆記

1 平面座標系下,向量和點一樣也用x,y表示,等於向量的起點到終點的位移,也相當於把起點平移到座標原點後終點的座標。向量基本運算 struct point typedef point vector 從程式實現上,vector只是point的別名 向量 向量 向量,點 向量 點 vector oper...

演算法競賽入門經典訓練指南 4 1 1學習筆記

點積 兩個向量v和w的點積等於兩者長度的乘積再乘上它們的夾角的余弦。夾角是指v到w的逆時針旋轉的角。夾角大於90度時積為負。255頁2段為止 double dot vector a,vector b double length vector a double angle vector a,vecto...