POJ3398 Perfect Service (树形DP)
作者:互联网
对于每个u要设置三维。
dp[u][0]表示u是服务器,以u为根的最小服务器数,其子节点既可以是,也可以不是,dp[u][0]+=min(d[v][0],d[v][1]);
dp[u][1]表示u不是服务器,但他的父节点时,此时u的子节点都不可能是,dp[u][1]+=dp[v][2];
dp[u][2]表示u及其父亲都不是服务器,u的子节点只有一个是服务器,枚举这个子节点,dp[u][2]=min(d[u][2],d[v1][2]+d[v2][2]+...+d[v][0]),但是我们这样枚举的话,复杂度是O(k2),我们发现求解dp[u][1]时已经求到了dp[v][2]的总和,那么我们可以借用这个优化到O(k):d[u][2]=min(d[u][2],d[u][1]-d[v][2]+d[v][0]).
最后的求解目标就是min(dp[1][0],dp[1][2]). (将1看成树根)
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=10000+5; 7 int n; 8 vector<int> E[maxn]; 9 int dp[maxn][3]; 10 11 void dfs(int u,int fa){ 12 dp[u][0]=1;//自身是服务器 13 dp[u][1]=0;//自身不是,父亲是 14 dp[u][2]=maxn;//自己和父亲都不是 15 int k=E[u].size(); 16 if(k==1&&fa!=0) return ; 17 for(int i=0;i<k;i++){ 18 int v=E[u][i]; 19 if(v==fa) continue; 20 dfs(v,u); 21 dp[u][0]+=min(dp[v][0],dp[v][1]); 22 dp[u][1]+=dp[v][2]; 23 } 24 for(int i=0;i<k;i++){ 25 int v=E[u][i]; 26 if(v==fa) continue; 27 dp[u][2]=min(dp[u][2],dp[u][1]-dp[v][2]+dp[v][0]); 28 } 29 } 30 31 int main(){ 32 int u,v; 33 while(~scanf("%d",&n)){ 34 for(int i=1;i<=n;i++) E[i].clear(); 35 for(int i=1;i<n;i++){ 36 scanf("%d%d",&u,&v); 37 E[u].push_back(v); 38 E[v].push_back(u);//正反向边都要建 39 } 40 dfs(1,0);//哪个节点作为树根并不影响 41 printf("%d\n",min(dp[1][0],dp[1][2])); 42 scanf("%d",&u); 43 if(u==-1) break; 44 } 45 return 0; 46 }
标签:Perfect,POJ3398,min,int,maxn,DP,服务器,include,dp 来源: https://www.cnblogs.com/yhxnoerror/p/16387892.html