题目链接:https://vjudge.net/problem/UVA-1218
题目大意:给你一棵无向树,让你求树的最小支配集,但是有一个要求是除最小支配集外剩下的任何一个结点不能同时连接支配集中的两个元素
解题报告:采用树形dp,只需将第一种状态的状态转移方程修改为$dp[i][0] = 1+sum_{ p[u]=i }min(dp[u][0],dp[u][2])$
AC代码:
1 #include<vector> 2 #include<cstdio> 3 #include<iostream> 4 #include<cmath> 5 #include<queue> 6 #include<stack> 7 #define numm ch-48 8 #define pd putchar(' ') 9 #define pn putchar(' ') 10 #define pb push_back 11 #define fi first 12 #define se second 13 #define fre1 freopen("1.txt","r",stdin) 14 #define fre2 freopen("2.txt","w",stdout) 15 using namespace std; 16 template <typename T> 17 void read(T &res) { 18 bool flag=false;char ch; 19 while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true); 20 for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm); 21 flag&&(res=-res); 22 } 23 template <typename T> 24 void write(T x) { 25 if(x<0) putchar('-'),x=-x; 26 if(x>9) write(x/10); 27 putchar(x%10+'0'); 28 } 29 const int maxn=10010; 30 const int N=1010; 31 const int inf=0x3f3f3f3f; 32 const int INF=0x7fffffff; 33 typedef long long ll; 34 struct node { 35 int v,net; 36 }e[maxn<<1]; 37 int cnt,n,head[maxn]; 38 int dp[maxn][3]; 39 void add(int u,int v) { 40 e[++cnt].v=v; 41 e[cnt].net=head[u]; 42 head[u]=cnt; 43 } 44 void DP(int u,int p) { ///u:当前结点,p:u的父结点 45 bool flag=false; ///标记是否有一个dp[to][0]<=dp[to][1] 46 int sum=0,inc=INF; 47 dp[u][2]=0; ///第三状态,当前结点未被选中 48 dp[u][0]=1; ///第一状态,当前结点被选中,dp[u][0]+1 49 for(int i=head[u];i!=-1;i=e[i].net) { 50 int to=e[i].v; 51 if(to==p) continue; ///to必须是u的子节点,不是父节点(由根dp到叶子) 52 DP(to,u); ///dp子节点 53 dp[u][0]+=min(dp[to][0],dp[to][2]); ///回溯,第一状态的转移 54 if(dp[to][0]<=dp[to][1]) { ///第二状态的判断 55 flag=true; 56 sum+=dp[to][0]; 57 } 58 else { 59 sum+=dp[to][1]; 60 inc=min(inc,dp[to][0]-dp[to][1]); 61 } 62 if(dp[to][1]!=INF&&dp[u][2]!=INF) ///第三状态的转移 63 dp[u][2]+=dp[to][1]; 64 else dp[u][2]=INF; ///根据定义dp[u][2]=(dp[to][1]的总和) 65 } 66 if(!flag&&inc==INF) ///判断当前是不是叶子结点 67 dp[u][1]=INF; 68 else 69 dp[u][1]=sum+(flag?0:inc); 70 } 71 int main() 72 { 73 while(scanf("%d",&n)!=EOF&&n) { 74 for(int i=1;i<=n;i++) 75 head[i]=-1,dp[i][0]=dp[i][1]=dp[i][2]=0,cnt=0; 76 for(int i=1;i<=n-1;i++) { 77 int a,b; 78 read(a),read(b); 79 add(a,b); 80 add(b,a); 81 } 82 DP(1,1); 83 write(min(dp[1][0],dp[1][1]));pn; 84 int flag; 85 read(flag); 86 if(flag==-1) break; 87 } 88 return 0; 89 }