題意:
給n,k,n個點的樹,k個點是黑色的,n-k點是白色的
給n-1條u,v,w,收益值是黑點兩兩距離之和,和白點兩兩距離之和的總值
求最大的收益值
思路:因為是樹形的,所以想到了求dp,dp[u][i] 求u為根的選有多少i個黑點的收益值,然後卡殼
翻了題解,發現dp[u][i] 求得是以u為根的 i 個黑點的貢獻值,就是有乙個通式:這條邊左邊的黑點*這條邊右邊的黑點*w+這條邊左邊的白色*這條邊右邊的白點*w
突然就豁然開朗了,仔細想想,我應該……應該個p 笨腦子不可能想到算貢獻的,告辭。這個通式如果是自己想到推出來,可能會吹一輩子
接下來就是在樹裡面進行dp了
f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]+val);
val就是那個通式:
這條邊左邊黑點數:k
這條邊右邊黑點數:k-k
這條邊左邊白點數:sz[v]-k,sz[v]是以u為根連線著 v 點的子樹點數
這條邊右邊的白點數:n-k-(sz[v]-k)
接下來就是類似01揹包操作吧
寫得過程各種wa,tle,參考了別人ac**,修修改改終於ac了
#includeusingnamespace
std;
#define ll long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 1000000007
const
int maxn=2010
;struct
nodea[maxn
<<1
];int
n,k1,cnt,tot,head[maxn];
ll f[maxn][maxn];
int sz[maxn]=;
il void add(int u,int
v,ll w)
void dfs(int u,int
qian)
dfs(v,u);
sz[u]+=sz[v];
}for(it i=head[u];i!=-1;i=a[i].next)
for(it j=min(sz[u],k1);j>=0;j--)}}
}}int
main()
dfs(
1,-1
);
//cout%lld\n
",f[1
][k1]);
return0;
}/*4 11 2 1
1 3 1
1 4 1
6*/
……希望在這條路上多堅持堅持
洛谷P3177 樹上染色
題目 一道非常好的樹形dp。狀態 dp u n 為u的子樹選n個黑點所能得到的收益最大值。則最終的結果就是 dp root k root 可以為任何值,為了方便,使 root 1 然後考慮怎麼狀態轉移,狀態轉移一般要從方程和邊界入手,考慮用揹包的思想,得到方程 dp now j max dp now...
洛谷 P3177 HAOI2015 樹上染色
懶得複製題面了直接傳送門吧 直接求點與點之間的距離感覺不是很好求,所以我們考慮換乙個求法。瞄了一眼題解 距離跟路徑上邊的長度有關,所以我們直接來看每一條邊的貢獻吧 這誰想得到啊 對於每一條邊,它的貢獻等於 一邊的白點數 另一邊的白點數 一邊的黑點數 另一邊的黑點數 邊權 然後。我又卡住了。再次瞄題解...
洛谷 P3177 HAOI2015 樹上染色
有一棵點數為 n 的樹,樹邊有邊權。給你乙個在 0 n 之內的正整數 k 你要在這棵樹中選擇 k 個點,將其染成黑色,並將其他 的 n k 個點染成白色 將所有點染色後,你會獲得黑點兩兩之間的距離加上白點兩兩之間的距離的和的受益。問受益最大值是多少。有點難想的dp 我果然太菜了 stdcall f ...