日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

洛谷P4383 林克卡特树

發(fā)布時(shí)間:2024/4/17 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洛谷P4383 林克卡特树 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題意:樹(shù)上最長(zhǎng)不相交k條鏈。

1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 5 typedef long long LL; 6 const int N = 300010; 7 8 struct Edge { 9 int nex, v; 10 LL len; 11 }edge[N << 1]; int top; 12 13 LL f[N][110][3]; 14 int e[N], n, k, siz[N]; 15 16 inline void add(int x, int y, LL z) { 17 top++; 18 edge[top].v = y; 19 edge[top].len = z; 20 edge[top].nex = e[x]; 21 e[x] = top; 22 return; 23 } 24 25 inline void exmax(LL &a, LL b) { 26 if(a < b) { 27 a = b; 28 } 29 return; 30 } 31 32 void DFS(int x, int fa) { 33 siz[x] = 1; 34 f[x][0][0] = 0; 35 for(int i = e[x]; i; i = edge[i].nex) { 36 int y = edge[i].v; 37 if(y == fa) { 38 continue; 39 } 40 DFS(y, x); 41 siz[x] += siz[y]; 42 // DP 43 for(int j = std::min(k, siz[x]); j >= 1; j--) { 44 for(int p = 0; p <= j && p <= siz[y]; p++) { // p in son 45 exmax(f[x][j][2], f[x][j - p + 1][1] + f[y][p][1] + edge[i].len); 46 exmax(f[x][j][0], f[x][j - p][0] + std::max(f[y][p][2], std::max(f[y][p][0], f[y][p][1]))); 47 exmax(f[x][j][1], f[x][j - p][1] + std::max(f[y][p][2], std::max(f[y][p][0], f[y][p][1]))); 48 exmax(f[x][j][2], f[x][j - p][2] + std::max(f[y][p][2], std::max(f[y][p][0], f[y][p][1]))); 49 exmax(f[x][j][1], f[x][j - p][0] + f[y][p][1] + edge[i].len); 50 } 51 } 52 } 53 for(int i = 1; i <= k && i <= siz[x]; i++) { 54 exmax(f[x][i][1], f[x][i - 1][0]); 55 } 56 /*printf("x = %d \n", x); 57 for(int i = 0; i <= k && i <= siz[x]; i++) { 58 printf("%d || 0 : %lld 1 : %lld 2 : %lld \n", i, f[x][i][0], f[x][i][1], f[x][i][2]); 59 }*/ 60 return; 61 } 62 63 int main() { 64 int n; 65 memset(f, ~0x3f, sizeof(f)); 66 scanf("%d%d", &n, &k); 67 k++; 68 int x, y; 69 LL z; 70 for(int i = 1; i < n; i++) { 71 scanf("%d%d%lld", &x, &y, &z); 72 add(x, y, z); 73 add(y, x, z); 74 } 75 DFS(1, 0); 76 printf("%lld\n", std::max(std::max(f[1][k][0], f[1][k][1]), f[1][k][2])); 77 return 0; 78 } 60分DP

?解:帶權(quán)二分/wqs二分/DP凸優(yōu)化。

一個(gè)比較常見(jiàn)的套路吧。

一般是求解有k限制的最優(yōu)化問(wèn)題。且隨著k的變化,極值函數(shù)上凸/下凸。

這時(shí)我們二分一個(gè)斜率去切它,會(huì)有一個(gè)斜率切到我們要的k。

感性理解一下,我們給這k個(gè)事物附上權(quán)值,然后權(quán)值增加的時(shí)候k就會(huì)變多,權(quán)值減小(可以為負(fù))的時(shí)候k會(huì)變少。

然后會(huì)有某個(gè)權(quán)值使得不限制k時(shí)的最優(yōu)值恰好選了k。這時(shí)候我們減去附加的權(quán)值即可。

本題就是給每條鏈加上一個(gè)權(quán)值。

還有一道題是k條白邊,剩下的選黑邊的最小生成樹(shù)。

1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 6 typedef long long LL; 7 const int N = 300010; 8 const LL INF = 1e17; 9 10 struct Edge { 11 int nex, v; 12 LL len; 13 }edge[N << 1]; int top; 14 15 LL f[N][3], D; 16 int g[N][3], n, k, e[N]; 17 18 inline void add(int x, int y, LL z) { 19 top++; 20 edge[top].v = y; 21 edge[top].len = z; 22 edge[top].nex = e[x]; 23 e[x] = top; 24 return; 25 } 26 27 inline void exmax(LL &a, int &c, LL b, int d) { 28 if(a < b || (a == b && c > d)) { 29 a = b; 30 c = d; 31 } 32 return; 33 } 34 35 void DFS(int x, int fa) { 36 f[x][0] = 0; // 初始化 不選鏈 37 for(int i = e[x]; i; i = edge[i].nex) { 38 int y = edge[i].v; 39 if(y == fa) { 40 continue; 41 } 42 DFS(y, x); 43 exmax(f[x][2], g[x][2], f[x][2] + f[y][2], g[x][2] + g[y][2]); 44 exmax(f[x][2], g[x][2], f[x][1] + f[y][1] + edge[i].len - D, g[x][1] + g[y][1] - 1); // 1 -> 2 45 46 exmax(f[x][1], g[x][1], f[x][1] + f[y][2], g[x][1] + g[y][2]); 47 exmax(f[x][1], g[x][1], f[x][0] + f[y][1] + edge[i].len, g[x][0] + g[y][1]); // 0 -> 1 48 49 exmax(f[x][0], g[x][0], f[x][0] + f[y][2], g[x][0] + g[y][2]); 50 } 51 exmax(f[x][1], g[x][1], f[x][0] + D, g[x][0] + 1); // 自己?jiǎn)为?dú)開(kāi)鏈 52 exmax(f[x][2], g[x][2], f[x][1], g[x][1]); 53 exmax(f[x][2], g[x][2], f[x][0], g[x][0]); 54 return; 55 } 56 57 inline bool check(LL mid) { 58 D = mid; 59 memset(g, 0, sizeof(g)); 60 memset(f, ~0x3f, sizeof(f)); 61 DFS(1, 0); 62 //printf("D = %lld \nf = %lld g = %d \n\n", D, f[1][2], g[1][2]); 63 return 0; 64 } 65 66 int main() { 67 68 scanf("%d%d", &n, &k); 69 LL z, r = 10, l; 70 k++; 71 for(int i = 1, x, y; i < n; i++) { 72 scanf("%d%d%lld", &x, &y, &z); 73 add(x, y, z); 74 add(y, x, z); 75 r += std::abs(z); 76 } 77 l = -r; 78 while(l < r) { 79 LL mid = (l + r + 1) >> 1; 80 //printf("%lld %lld mid = %lld \n", l, r, mid); 81 check(mid); 82 if(g[1][2] == k) { 83 printf("%lld\n", f[1][2] - k * mid); 84 return 0; 85 } 86 if(g[1][2] > k) { 87 r = mid - 1; 88 } 89 else { 90 l = mid; 91 } 92 } 93 94 check(r); 95 printf("%lld\n", f[1][2] - k * r); 96 return 0; 97 } AC代碼

本題只要整數(shù)二分就行了。

負(fù)數(shù)二分用右移,是向下取整。

細(xì)節(jié):可能最優(yōu)點(diǎn)不是凸包上的頂點(diǎn),是一條邊中間。我們這時(shí)找到靠左的那個(gè)頂點(diǎn),然后用這個(gè)斜率 * k就行了。

實(shí)數(shù)版:

1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 6 typedef long long LL; 7 const int N = 300010; 8 const LL INF = 1e17; 9 const double eps = 1e-6; 10 11 struct Edge { 12 int nex, v; 13 LL len; 14 }edge[N << 1]; int top; 15 16 double f[N][3], D; 17 int g[N][3], n, k, e[N]; 18 19 inline void add(int x, int y, LL z) { 20 top++; 21 edge[top].v = y; 22 edge[top].len = z; 23 edge[top].nex = e[x]; 24 e[x] = top; 25 return; 26 } 27 28 inline void exmax(double &a, int &c, double b, int d) { 29 // if(a < b || (a == b && c > d)) { 30 if(a < b) { 31 a = b; 32 c = d; 33 } 34 return; 35 } 36 37 void DFS(int x, int fa) { 38 f[x][0] = 0; // 初始化 不選鏈 39 for(int i = e[x]; i; i = edge[i].nex) { 40 int y = edge[i].v; 41 if(y == fa) { 42 continue; 43 } 44 DFS(y, x); 45 exmax(f[x][2], g[x][2], f[x][2] + f[y][2], g[x][2] + g[y][2]); 46 exmax(f[x][2], g[x][2], f[x][1] + f[y][1] + edge[i].len - D, g[x][1] + g[y][1] - 1); // 1 -> 2 47 48 exmax(f[x][1], g[x][1], f[x][1] + f[y][2], g[x][1] + g[y][2]); 49 exmax(f[x][1], g[x][1], f[x][0] + f[y][1] + edge[i].len, g[x][0] + g[y][1]); // 0 -> 1 50 51 exmax(f[x][0], g[x][0], f[x][0] + f[y][2], g[x][0] + g[y][2]); 52 } 53 exmax(f[x][1], g[x][1], f[x][0] + D, g[x][0] + 1); // 自己?jiǎn)为?dú)開(kāi)鏈 54 exmax(f[x][2], g[x][2], f[x][1], g[x][1]); 55 exmax(f[x][2], g[x][2], f[x][0], g[x][0]); 56 return; 57 } 58 59 inline bool check(double mid) { 60 D = mid; 61 memset(g, 0, sizeof(g)); 62 //memset(f, ~0x3f, sizeof(f)); 63 for(int i = 1; i <= n; i++) { 64 f[i][0] = f[i][1] = f[i][2] = -INF; 65 } 66 DFS(1, 0); 67 //printf("D = %lld \nf = %lld g = %d \n\n", D, f[1][2], g[1][2]); 68 return 0; 69 } 70 71 int main() { 72 73 scanf("%d%d", &n, &k); 74 LL z; 75 double r = 10, l; 76 k++; 77 for(int i = 1, x, y; i < n; i++) { 78 scanf("%d%d%lld", &x, &y, &z); 79 add(x, y, z); 80 add(y, x, z); 81 r += std::abs(z); 82 } 83 l = -r; 84 while(fabs(r - l) > eps) { 85 double mid = (l + r) / 2; 86 //printf("%lld %lld mid = %lld \n", l, r, mid); 87 check(mid); 88 if(g[1][2] == k) { 89 printf("%.0f\n", f[1][2] - k * mid); 90 return 0; 91 } 92 if(g[1][2] > k) { 93 r = mid; 94 } 95 else { 96 l = mid; 97 } 98 } 99 100 check(r); 101 printf("%.0f\n", f[1][2] - k * r); 102 return 0; 103 } AC代碼

?

轉(zhuǎn)載于:https://www.cnblogs.com/huyufeifei/p/10396505.html

總結(jié)

以上是生活随笔為你收集整理的洛谷P4383 林克卡特树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。