學習筆記(DP) 刷題日記

2021-10-24 09:20:20 字數 3207 閱讀 5817

貪心的思想,從右往左把每列都取完或剩下乙個(取餘2)。

觀察畫圖可以發現,若剩下乙個的兩列之間間隔列數為偶數的話,是可以通過最底下一行使得這兩列剩下的那乙個合併使得貢獻加1。

#include

#define ll long long

#define endl '\n'

using

namespace std;

const

int maxn=

3e5+5;

stack <

int> s;

intmain()

} cout<}

#include

#define ll long long

#define endl '\n'

using

namespace std;

const

int maxn=

505;

const

int inf=

0x3f3f3f3f

;int dp[maxn]

[maxn]

;int

main()

}}cout<[n-1]+

1<}

分組揹包

#include

#define ll long long

#define endl '\n'

using

namespace std;

const

int inf=

0x3f3f3f3f

;int f[

100005

],h[15]

,num[

100005];

int dp[

5005];

intmain()

for(

int i=

1;i<=n;i++

)for

(int i=

1;i<=k;i++

) cin>>h[i]

; ll ans=0;

for(

int i=

1;i<=

100000

;i++)}

} ans+

=dp[num[i]];

memset

(dp,0,

sizeof

(dp));

} cout<}

樹上dp + 貪心

f(x) 表示待x的子樹全部完成安裝的時間

g(x) 表示遍歷子樹回到x所需要的時間

f(x) - g(x) 即等待的時間

貪心可得,等待越久的應當越早被安裝(自行腦補)

f[u] = max(f[u],f[son[i]]+1+g[u]);

//+1是因為安裝時間大於1,回來的那個1可以被忽略

g[u] += 2+g[son[i]];

//遍歷u的子節點的時間以及來回+2,因為貪心所以g[u]從0開始遞增

#include

#define ll long long

#define endl '\n'

using

namespace std;

const

int maxn=

1e6+5;

struct nodee[maxn]

;int cnt,knt,f[maxn]

,g[maxn]

,head[maxn]

,s[maxn]

,son[maxn]

;void

add(

int x,

int y)

bool

cmp(

int x,

int y)

void

dfs(

int u,

int fa)

}int

main()

dfs(1,

-1);

cout<<

max(f[1]

,g[1

]+s[1]

)<}

樹上dp

已知乙個節點只有乙個父親節點,那麼出現自環時一定是根節點以及其父親節點(也是某乙個葉子節點),所以通過並查集找環,強制選擇這兩個點中的乙個,另乙個不選,對兩種情況跑樹上dp(這裡跟入門題沒有上司的舞會一摸一樣)取max加入最後的答案中即可。注意最後答案要用long long來存。

#include

#define ll long long

#define endl '\n'

using

namespace std;

const

int maxn =

1e6+5;

int val[maxn]

, fa[maxn]

, head[maxn]

;bool vis[maxn]

;ll dp[maxn][2

],ans;

int cnt, n, root;

struct nodee[maxn]

;void

add(

int from,

int to)

void

cal(

int x)

else dp[now][1

]=-maxn;

//選該點貢獻負無窮,說明強制不選 }}

void

find_circle

(int x)

cal(root)

;//強制選第乙個點

ll cur =

max(dp[root][0

],dp[root][1

]); root = fa[root]

;cal

(root)

;//強制選另乙個點

ans +

=max

(cur,

max(dp[root][0

],dp[root][1

]));

return;}

intmain()

for(

int i =

1; i<= n; i++)if

(!vis[i]

)find_circle

(i);

cout << ans << endl;

}

leetcode 刷題日記

將兩個有序鍊錶合併為乙個新的有序鍊錶並返回。新煉表是通過拼接給定的兩個鍊錶的所有節點組成的。採用乙個帶頭節點的指標head鏈結合併後的新指標,乙個空指標pre進行迴圈載入兩個鍊錶中的節點比較兩個鍊錶節點的值,pre指標鏈結較小值的鍊錶的節點,依次遍歷兩個鍊錶,直到乙個為空停止迴圈。複雜度分析 時間複...

leetcode 刷題日記

題目 給出兩個 非空 的鍊錶用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式儲存的,並且它們的每個節點只能儲存 一位 數字。如果,我們將這兩個數相加起來,則會返回乙個新的鍊錶來表示它們的和。您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。解題思路 按照最長鍊錶的長度遍歷兩個...

leetcode刷題日記

給你兩個陣列,arr1 和 arr2,arr2 中的元素各不相同 arr2 中的每個元素都出現在 arr1 中 對 arr1 中的元素進行排序,使 arr1 中項的相對順序和 arr2 中的相對順序相同。未在 arr2 現過的元素需要按照公升序放在 arr1 的末尾。示例 輸入 arr1 2,3,1...