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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P4149 [IOI2011]Race

發布時間:2023/12/3 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P4149 [IOI2011]Race 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

P4149 [IOI2011]Race

題意:

給一棵樹,每條邊有權。求一條簡單路徑,權值和等于 k,且邊的數量最小。

題解:

用t[i]:長度為i的路徑包含的最少邊數
按照子樹順序,依次用dep[u]+t[K-d[u]]更新ans,更新t數組,最后遍歷子樹恢復t數組

代碼:

85分代碼,不知道哪錯了

//#pragma optimize("Ofast") #include <bits/stdc++.h> #define MAXN 4000005 #define MAXK 10000007 #define inf 20000007 using namespace std; typedef long long ll;int N, K; struct edge {int v;ll w;edge(int v= 0, ll w= 0) : v(v), w(w){} };vector<edge> adj[MAXN];int vis[MAXN]; ll d[MAXN]; int sz[MAXN]; int rt, cnt; int t[MAXK], ans= inf; int dep[MAXN]; void dfs_rt(int u, int fa, int tot) {//++cnt;sz[u]= 1;int v, w, n= 0;for (int k= 0; k < adj[u].size(); k++) {v= adj[u][k].v;if (v == fa || vis[v])continue;dfs_rt(v, u, tot);sz[u]+= sz[v];n= max(n, sz[v]);}n= max(n, tot - sz[u]);if (2 * n <= tot)rt= u; }void dfs1(int u, int fa) {++cnt;if (K >= d[u])ans= min(ans, dep[u] + t[K - d[u]]);int v, w;for (int k= 0; k < adj[u].size(); k++) {v= adj[u][k].v;w= adj[u][k].w;if (v == fa || vis[v])continue;d[v]= d[u] + w;dep[v]= dep[u] + 1;dfs1(v, u);} }void dfs2(int u, int fa, int flag) {if (K >= d[u]) {if (flag == 1)t[d[u]]= min(t[d[u]], dep[u]);elset[d[u]]= inf;}int v;for (int k= 0; k < adj[u].size(); k++) {v= adj[u][k].v;if (v == fa || vis[v])continue;dfs2(v, u, flag);} } void work(int u, int fa, int tot) {dfs_rt(u, fa, tot);u= rt;vis[u]= 1;d[u]= 0;t[0]= 1;int v, w;for (int k= 0; k < adj[u].size(); k++) {v= adj[u][k].v;w= adj[u][k].w;if (vis[v])continue;cnt= 0;d[v]= w; //路徑dep[v]= 1;dfs1(v, u);sz[v]= cnt;dfs2(v, u, +1);}dfs2(u, 0, -1);for (int k= 0; k < adj[u].size(); k++) {v= adj[u][k].v;if (vis[v])continue;work(v, u, sz[v]);} }int main() {scanf("%d%d", &N, &K);memset(t, inf, sizeof(t));int u, v, w;for (int i= 1; i < N; i++) {scanf("%d%d%d", &u, &v, &w);u++;v++;adj[u].push_back(edge(v, w));adj[v].push_back(edge(u, w));}memset(t, inf, sizeof t);t[0]= 1;work(1, 0, N);printf("%d\n", ans >= N ? -1 : ans);return 0; }

AC代碼:

#include<bits/stdc++.h> using namespace std; const int maxn=200020,maxk=1000100; #define FOR(i,a,b) for(int i=(a);i<=(b);i++) #define ROF(i,a,b) for(int i=(a);i>=(b);i--) #define MEM(x,v) memset(x,v,sizeof(x)) inline int read(){char ch=getchar();int x=0,f=0;while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return f?-x:x; } int n,k,el,head[maxn],to[maxn*2],w[maxn*2],nxt[maxn*2]; int rt,tot,sz[maxn],son[maxn],mine[maxk],ans=INT_MAX,dis1[maxn],dis2[maxn],dl; bool vis[maxn]; inline void add(int u,int v,int w_){to[++el]=v;w[el]=w_;nxt[el]=head[u];head[u]=el; } void getrt(int u,int f){ //求重心sz[u]=1;son[u]=0;for(int i=head[u];i;i=nxt[i]){//v=to[i]不是必需的,可以去掉if(to[i]==f || vis[to[i]]) continue;getrt(to[i],u);sz[u]+=sz[to[i]];son[u]=max(son[u],sz[to[i]]);}son[u]=max(son[u],tot-sz[u]);if(son[u]<son[rt]) rt=u; } void getdis(int u,int f,int d1,int d2){ //dfs將子樹的信息記錄下來(d1是權值和,d2是邊數)if(d1>k) return;dis1[++dl]=d1;dis2[dl]=d2;for(int i=head[u];i;i=nxt[i]){//同上if(to[i]==f || vis[to[i]]) continue;getdis(to[i],u,d1+w[i],d2+1);} } void getans(int u){ //計算經過u的路徑的答案mine[0]=0;dl=0; //mine[0]是0!因為一個端點是u的路徑也要考慮,而且0不會被其它子樹記錄到for(int i=head[u];i;i=nxt[i]){if(vis[to[i]]) continue;int pdl=dl; //前面的子樹有多少元素getdis(to[i],u,w[i],1); //注意調用時w[i]和1FOR(j,pdl+1,dl) ans=min(ans,mine[k-dis1[j]]+dis2[j]);//更新答案FOR(j,pdl+1,dl) mine[dis1[j]]=min(mine[dis1[j]],dis2[j]);//更新桶}FOR(i,1,dl) mine[dis1[i]]=1e9; } void getall(int u){ //點分治主過程vis[u]=true;getans(u);for(int i=head[u];i;i=nxt[i]){if(vis[to[i]]) continue;tot=sz[to[i]];rt=0;getrt(to[i],u);getall(rt);} } int main(){n=read();k=read();FOR(i,1,n-1){int u=read()+1,v=read()+1,w=read(); //編號從0開始add(u,v,w);add(v,u,w);}son[0]=(tot=n)+1; //son[0]設為INFgetrt(1,0);MEM(mine,0x3f);getall(rt);printf("%d\n",ans>=n?-1:ans); //最短長度超過n就是無解 }

總結

以上是生活随笔為你收集整理的P4149 [IOI2011]Race的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。