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