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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

luogu P4183 Cow at Large P (暴力吊打点分治)(内有时间复杂度证明)

發布時間:2025/4/16 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 luogu P4183 Cow at Large P (暴力吊打点分治)(内有时间复杂度证明) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題面

貝茜被農民們逼進了一個偏僻的農場。農場可視為一棵有N個結點的樹,結點分別編號為 1,2,…,N 。每個葉子結點都是出入口。開始時,每個出入口都可以放一個農民(也可以不放)。每個時刻,貝茜和農民都可以移動到相鄰的一個結點。如果某一時刻農民與貝茜相遇了(在邊上或點上均算),則貝茜將被抓住。抓捕過程中,農民們與貝茜均知道對方在哪個結點。

請問:對于結點 i\((1\leq i\leq N)\),如果開始時貝茜在該結點,最少有多少農民,她才會被抓住。

分析

先考慮問題的簡化版,對于給定的起點s求出答案

設dist(x,y)表示x,y兩點之間的距離

我們發現,對于某一個節點x,若$dist(s,x) \geq \min {dist(x,u) } $ 其中u為x的子樹中的葉子節點,那么從x走到s的時

候就會被抓住.$\min {dist(x,u) } $可以通過一次BFS預處理出來

顯然奶牛越早被抓住更好,從節點s出發DFS,只要當前節點x滿足上述條件,則ans++,并不訪問x子樹中的節點。因為如果在x點被抓住了,它就不會到比x深度更大的節點去了

這樣的復雜度顯然是\(O(n^2)\)


有一個玄學優化,可以通過此題,方法如下

1.DP一遍求出每個點到最近的葉子節點的距離dp[x]

2.DFS,把鏈縮成一條邊,因為可以發現不管在鏈的哪里攔截都是一樣的

3.每次暴力,當dp[x]<=dist(x,root)的時候ans++,return

可以證明把鏈縮掉之后是\(O(n\sqrt{n})\)

由于沒有鏈,我們可以把模型簡化為一個滿k叉樹(k>1),每次暴力DFS,顯然DFS的深度不超過樹的深度的1/2,即\(O(log_kn)\)

訪問的子樹大小為
\[1+k+k^2+...+k^{\frac{1}{2}\log_kn}=\frac{k^{(\frac{1}{2}\log_kn)+1}-1}{k-1}=\frac{k^{\log_kn} \times \sqrt k-1}{k-1}=\frac{k\sqrt{n}-1}{k-1}=\sqrt{n}+\frac{\sqrt{n}-1}{k-1}\]

顯然當k=2最大,為\(2\sqrt{n}-1\),

所以總時間復雜度為\(O(n\sqrt{n})\),與分塊相同,且常數遠小于點分治

代碼

#include<iostream> #include<cstdio> #include<queue> #include<cstring> #define maxn 100005 #define INF 0x3f3f3f3f using namespace std; inline void qread(int &x){x=0;char c=getchar();while(c<'0'||c>'9'){c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} } inline void qprint(int x){if(x==0){putchar('0');return;}else{if(x>=10) qprint(x/10);putchar(x%10+'0');} } int n,k; struct edge{int from;int to;int next;int nfrom;int nto;int len; }E[maxn<<1]; int head[maxn]; int deg[maxn]; int sz=1; void add_edge(int u,int v){deg[u]++;deg[v]++;sz++;E[sz].from=u;E[sz].to=v;E[sz].next=head[u];head[u]=sz; }int dp[maxn];//表示離x最近的葉子節點到x的距離 //不能從一個根開始DFS,因為此時根不定, //到一個點最近的葉子節點不一定在DFS時的子樹里,而可能在它上方 void bfs(){queue<int>q;for(int i=1;i<=n;i++){if(deg[i]<=1){q.push(i);dp[i]=0;}else dp[i]=INF;}while(!q.empty()){int x=q.front();q.pop();for(int i=head[x];i;i=E[i].next){int y=E[i].to;if(dp[y]==INF){dp[y]=min(dp[y],dp[x]+1);q.push(y);}}} } int s,t,d; void dfs2(int x,int fa,int deep){if(fa!=0&&deg[x]!=2){s=x;t=fa;d=deep;return;}for(int i=head[x];i;i=E[i].next){int y=E[i].to;if(y!=fa){dfs2(y,x,deep+1);E[i].nto=s;E[i].nfrom=t;E[i].len=d-deep;}} } int ans=0; void dfs3(int x,int fa,int deep){if(deep>=dp[x]){ans++;return;}for(int i=head[x];i;i=E[i].next){int y=E[i].to;if(y!=fa){dfs3(E[i].nto,E[i].nfrom,deep+E[i].len);}} } int main(){int u,v;qread(n);for(int i=1;i<n;i++){qread(u);qread(v);add_edge(u,v);add_edge(v,u);} for(int i=1;i<=n;i++) deg[i]/=2;bfs();for(int i=1;i<=n;i++){if(deg[i]!=2) dfs2(i,0,0);}for(int i=1;i<=n;i++){ans=0;dfs3(i,0,0);qprint(ans);putchar('\n');} }

轉載于:https://www.cnblogs.com/birchtree/p/10567833.html

總結

以上是生活随笔為你收集整理的luogu P4183 Cow at Large P (暴力吊打点分治)(内有时间复杂度证明)的全部內容,希望文章能夠幫你解決所遇到的問題。

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