树形dp裸题,不过输入是真的恶心,要字符串读入考虑数字大于等于10的情况
dp[i][j]表示i的子树在j状态的最小的边集覆盖,j为0表示不选当前结点,1表示选
转移方程(u->x是u的所有子节点)dp[u][0]+=dp[x][1],dp[u][1]+=min(dp[x][0],dp[x][1]),dp[u][1]+=1(要选自己)
#include<cstdio> #include<iostream> #include<cstring> #define fi first #define se second #define mp make_pair #define pb push_back #define pii pair<int,int> #define C 0.5772156649 #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 using namespace std; using namespace __gnu_cxx; const double g=10.0,eps=1e-7; const int N=1500+10,maxn=60000+10,inf=0x3f3f3f3f; struct edge{ int to,Next; }e[N<<2]; int dp[N][2]; int head[N],cnt; void add(int u,int v) { e[cnt].to=v; e[cnt].Next=head[u]; head[u]=cnt++; } void dfs(int u,int f) { dp[u][1]=1; for(int i=head[u];~i;i=e[i].Next) { int x=e[i].to; if(x==f)continue; dfs(x,u); dp[u][0]+=dp[x][1]; dp[u][1]+=min(dp[x][0],dp[x][1]); } } int main() { ios::sync_with_stdio(false); cin.tie(0); int n; while(cin>>n) { memset(head,-1,sizeof head); cnt=0; for(int i=0; i<n; i++) { string s; cin>>s; int a=0,id=0; while(id+1<s.size()&&s[id+1]!=‘:‘)id++; // cout<<id<<endl; for(int i=0;i<=id;i++)a=a*10+(int)(s[i]-‘0‘); // cout<<a<<endl; int k=0,id1=id+3; while(id1+1<s.size()&&s[id1+1]!=‘)‘)id1++; for(int i=id+3;i<=id1;i++)k=k*10+(int)(s[i]-‘0‘); // cout<<k<<endl; while(k--) { int b; cin>>b; add(a,b); add(b,a); } } memset(dp,0,sizeof dp); dfs(1,-1); cout<<min(dp[1][0],dp[1][1])<<endl; } return 0; } /************ 11 0:(10) 1 2 3 4 5 6 7 8 9 10 1:(0) 2:(0) 3:(0) 4:(0) 5:(0) 6:(0) 7:(0) 8:(0) 9:(0) 10:(0) ************/
时间: 2024-10-29 15:22:46