zoj-4007(樹形dp)
阿新 • • 發佈:2018-11-30
通過模擬可以得到一個dp公式:
如果為0的話轉移方程為:dp[0][u] += min(dp[1][v]+1,dp[0][v]),
如果為1的話轉移方程為:dp[1][u] += min(dp[1][v],dp[0][v]+1),
如果為-1的話轉移方程為:dp[0][u] += min(dp[1][v]+1,dp[0][v]);
dp[1][u] += min(dp[1][v],dp[0][v]+1);
最後的答案就是min(dp[1][1],dp[0][1]),建議自己模擬一下dp過程;
程式碼如下:
#include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> using namespace std; const int mx = 1e5+5; const int inf = 1e6; int n,m; vector<int>g[mx]; int a[mx]; int dp[2][mx]; voiddfs(int u,int fa) { if(a[u]==-1) dp[0][u] = dp[1][u] = 0; else dp[a[u]][u] = 0;/*將符合題意的初始狀態定為0*/ for(int i=0;i<g[u].size();i++)/*把與該點連線的點掃一次*/ { int v=g[u][i]; if(v!=fa)/*要求不能是父節點*/ { dfs(v,u); if(a[u]==-1) { dp[0][u] += min(dp[0][v],dp[1][v]+1); dp[1][u] += min(dp[0][v]+1,dp[1][v]); } else dp[a[u]][u] += min(dp[a[u]][v],dp[a[u]^1][v]+1); } } } int main() { int t,q,ca = 1; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); dp[0][i] = dp[1][i] = inf; g[i].clear(); } for(int i = 1; i < n; i++) { int u,v; scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u);/*將與該節點連線的點儲存起來*/ } dfs(1,1);/*從根節點開始dp*/ printf("%d\n",min(dp[0][1],dp[1][1])); } return 0; }