洛谷P2607 騎士 樹形dp

2021-10-03 20:37:34 字數 1198 閱讀 3689

思路:首先我們想到可以對相互憎惡的倆個騎士連邊,這樣就得到了乙個圖,有多個連通塊,並且每個連通塊中最多只有乙個環。如果每個連通塊都是一顆樹,那麼這個問題就很簡單~每個節點都是選或者不選。

idea1:我想可不可以把這個比樹多一條邊的圖,變成一棵樹來處理,那麼就是要刪掉環上的一條邊。考慮刪掉這條邊(u,v)的影響是什麼,影響是u,v兩點可能同時被選,產生錯誤的答案。

我的解決辦法是把邊刪了的同時,分三種情況,1.把v[u]變成0 2.把v[v]變成0 3.把v[u],v[v]都變成0;因為如果乙個點都變成0那答案中一定不包涵這個點。因為去掉這個點答案不會變劣;

產生的問題:

1.因為要刪邊,我用的是setg[maxn]。這樣複雜度就多了乙個log。而且分三種情況,所以常數就比較大。t的我人都傻了

2.用set存會比vector消耗更多的記憶體。mle。。。

3.cin即使加了流同步還是比scanf慢。。。所以還是用scanf吧

4.用陣列實現鄰接表會比用vector快一些

解決辦法:

看了題解裡的**,發現這條邊其實不用刪,只要把u當成根,把v當成根分別算就行了,這樣常數就小了。並且存圖可以直接用鄰接表,只要把其中一條邊特判掉剩下的就是一棵樹了

**如下:

#includeusing namespace std;

#define maxn 1000010

#define ll long long

#define pii pairll v[maxn];int vis[maxn];

ll dp[maxn][2];

int sta,en,e;//環上的邊

struct edge

e[maxn*2];

int st[maxn],tot=0;

void add(int x,int y)

void dfs1(int now,int fa)//fa是上一邊

dfs1(e[i].to,i);

} return ;

}void dfs2(int now,int fa)

return ;

}int main()

// for(int i=0;ill ans=0;

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

// cout

return 0;

}

洛谷P2607題解

想要深入學習樹形dp,我的部落格。本題的dp模型同 p1352 沒有上司的舞會。本題的難點在於如何把基環樹dp轉化為普通的樹上dp。考慮斷邊和換根。先找到其中的乙個環,在上面隨意取兩個點,斷開這兩個點的邊,使其變為一棵普通樹。以其中的一點為樹根做樹形dp,再以另一點為樹根再做一次樹形dp,因為相鄰的...

洛谷P2607 騎士 沒有上司的舞會

題目大意 給定乙個 n 個點的外向樹森林,點有點權。從該樹中選出若干頂點組成乙個集合,滿足任意相鄰的兩個頂點不同時出現在該集合中,求這樣集合中點權和的最大值為多少。題解 與樹相比,該題多了環這個結構。對於環上任意一條邊來說,邊的端點不可能同時被選取,因此,可以選擇環上任意一條邊,將其斷開,答案不變。...

P2607(基環樹 樹形DP)

最近想要刷部落格數,給自己一種努力的假象,最好的方式當然是給做過的題目做一篇題解啦 標準樹形dp題,選了父節點不能選子節點,唯一難點是基環樹的處理 先找環,只需要找到環上的兩個點就行了,其他點不用一起找出,用dfs,斷邊 斷邊的具體操作是 分別將邊上的兩個點設為根進行樹形dp,但兩個點之間還有的關係...