ACM DP作業整理 待補

2021-09-29 20:48:26 字數 4210 閱讀 4811

難度中等

a:二進位制拆分 + 01揹包;

n可以拆分為 1、2、4 …… 2 ^ (k - 1)、n - 2 ^ k + 1

m = 100000,複雜度是 mnlogn,不知道為啥能過……

b:完全揹包,滾動陣列優化;

c:01揹包;

d:乙個包裝的01揹包問題,將錢數看作價值,**的概率看作體積,但是注意概率不能靠加減法計算,而是乘除法;

考慮到陣列下標不能是小數,所以讓下標變成價值,那麼從大到小遍歷所有可能的價值,第乙個體積小於總體積的價值就是答案;

用滾動陣列優化;

定義dp[i] : 表示 搶劫 i 價值的財物**的最小概率;

dp[0] = 0,dp[i] = inf;

轉移:dp[j] = min(dp[j],dp[j - w[i]] * (1.0 - v[i]) + (1.0 - dp[j - w[i]]) * v[i] +dp[j - w[i]] * v[i]);

但是這樣實在是太長了,考慮換一種狀態;

dp[i] : 表示 搶劫 i 價值的財物逍遙法外的最大概率;

dp[0] = 1,dp[i] = 0;

轉移 :dp[j] = max(dp[j],dp[j - w[i]] * (1.0 - v[i]));

注意不要漏掉狀態(加粗部分),找出狀態的所有情況是關鍵點

e:證明你學過動態規劃;

f:在另一篇博文裡講的很清楚了;

g:證明你學過動態規劃;

h:不難,但還是想了很長時間,首先要優化狀態,讓差的平方最小,則考慮到排序;

可以證明,排序後,當且僅當某數和前面乙個數或者它後面乙個數成對時,總的和最小;

因為 對於4個數,差是a,b,c。(a + b)^ 2 <= (a + c) ^ 2 + (b + c) ^ 2 和 (a + b + c) ^ 2 + b ^ 2;

dp[i][j] : 前i個數選2 * j個數字d的最小值;

dp[i][j] = min( dp[i - 1][j],dp[i - 2][j - 1] + (a[i] - a[i - 1]) * (a[i] - a[i - 1]) ); 

注意初始化dp[i][0] = 0; 因為dp[i][j] 會由此狀態轉移過去;

因為這個點,wa了很長時間。

所以當確定方程狀態正確時,應注意邊界和初始化是否正確;

i:樹形dp,和j題差不多;

j:樹形dp;

dp[ii][0/1] : 表示是否選i點;

dp[i][0] += max(dp[v][1],do[v][0]); v是i的子結點;

dp[i][1] += dp[v][0];

k:樹形dp + 揹包:

dp[x][i][j],表示以x為根的子樹中,前i個子結點,攻破j個城市獲得最大的寶物價值;

用滾動陣列可以優化掉一維;

a:

#include#include#include#includeusing namespace std;

const int maxn = 100001 + 11;

int v[maxn],dp[maxn],cnt[maxn];

int n,v,ans,tot,t;

void solve()

v[++ tot] = (cnt[i] - (t << 1) + 1) * v[i];

} for(int i = 1;i <= tot;i ++)

for(int j = v;j >= v[i];j --)

dp[j] |= dp[j - v[i]];

for(int i = 1;i <= v;i ++) if(dp[i]) ans ++;

cout << ans << "\n";

return;

}int main()

d:

第一種:

#include#include#include#includeusing namespace std;

const int maxn = 20001 + 22;

int n,t,sum;

int w[maxn];

double v,v[maxn],dp[maxn],inf = 214483.0;

void solve()

for(int i = 0;i <= sum;i ++) dp[i] = inf;

dp[0] = 0.0;

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

for(int j = sum;j >= w[i];j --)

if(dp[j - w[i]] <= 1.0)

for(int i = sum;i >= 0;i --) }}

int main()

第二種:

#include#include#include#includeusing namespace std;

const int maxn = 20001 + 22;

int n,t,sum;

int w[maxn];

double v,v[maxn],dp[maxn],inf = 214483.0;

void solve()

for(int i = 0;i <= sum;i ++) dp[i] = inf;

dp[0] = 0.0;

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

for(int j = sum;j >= w[i];j --)

if(dp[j - w[i]] <= 1.0)

for(int i = sum;i >= 0;i --) }}

int main()

h: 

#include#include#include#includeusing namespace std;

const int maxn = 2001 + 22;

int a[maxn],ma[maxn],dp[maxn][maxn];

int n,k;

void solve()

int main()

i:

#include#include#include#include#includeusing namespace std;

vectorg[1603];

int dp[1603][2];

int n;

void dfs(int x,int f)

return;

}void solve()

} dfs(0,-1);

cout << min(dp[0][0],dp[0][1]) << endl;

return;

}int main()

j:

#include#include#include#include#includeusing namespace std;

const int maxn = 10001;

int fa[maxn],a[maxn],dp[maxn][2];

int n,root;

vectorg[maxn];

void dfs(int x)

return;

}void solve()

while(1)

int x = 1;

while(fa[x] != -1) x = fa[x];

root = x,dfs(root);

cout << max(dp[root][0],dp[root][1]) << endl; }}

int main()

k:

#include#include#include#include#includeusing namespace std;

const int maxn = 205;

int size[maxn],a[maxn],dp[maxn][maxn];

int n,m,ans;

vectorg[maxn];

void init()

void dfs(int x)

return;

}void solve()

dfs(0);

cout << dp[0][m + 1] << endl;

return;

}int main()

return 0;

}

二分內容整理(待補充

內容來演算法競賽高階指南,我把自認為的重點寫了下來,方便檢視 while l 1 if a mid x r mid else l mid 1 cout 1 if a mid x l mid else r mid 1 cout關鍵是倆個寫法的的mid的取值,如果對第二段 也是 l r 1,那麼當r l...

java作業整理

題意 1.宣告乙個獅子類 lion 繼承自食肉動物類 carnivore 並且實現 runnable 介面。要求 1 寫出runnable 介面,並定義乙個返回值為空的方法 run 2 寫出 carnivore類,定義為抽象,封裝一屬性 int legs 寫出含有引數 int legs 的構造方法 ...

Java作業整理

題意 編寫乙個名為square 正方形 的類,並按要求完成如下封裝 要求 1 乙個名為 side 的double 私有資料域表示三條邊 2 乙個能建立帶指定引數引數 s1的構造方法 3 實現 comparable cloneable 介面。5 編寫方法,求 square 正方形 類物件的周長,返回 ...