传送门:http://codeforces.com/problemset/problem/581/F
思路:设f[i][cnt][col]表示i的子树中,黑节点为cnt,i的颜色为col时,最小的端点颜色不同的边的数量。
转移就是 f[x][cnt][col]=min(f[son[x]][i][col_son]+f[x][cnt-i][col]+(col!=col_son));
看起来这是O(n^3)的,实际上这是O(n^2)的
对于一个点x,对x操作的复杂度就是
观察一下就会发现,每对叶子节点(x,y)只会在lca(x,y)处对复杂度有一次贡献
于是复杂度就是O(n^2)的了。
#include<cstdio> #include<cstring> #include<algorithm> const int maxn=5010,maxm=10010; using namespace std; int n,m,pre[maxm],now[maxn],son[maxm],val[maxm],f[maxn][maxn][2],g[maxn][2],siz[maxn],tot,in[maxn];bool isl[maxn]; void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b,in[b]++;}//0 white 1 black void dfs(int x,int fa){ if (isl[x]){siz[x]=1,f[x][0][0]=f[x][1][1]=0;return;} f[x][0][0]=f[x][0][1]=0; for (int y=now[x];y;y=pre[y])if (son[y]!=fa){ dfs(son[y],x); //printf("fuckpp%d %d ",son[y],siz[x]); memset(g,63,sizeof(g)); for (int i=siz[x];i>=0;i--) for (int j=siz[son[y]];j>=0;j--){ //if (son[y]==8&&x==5) printf("%d %d ",i,j); g[i+j][0]=min(g[i+j][0],f[x][i][0]+f[son[y]][j][0]); g[i+j][1]=min(g[i+j][1],f[x][i][1]+f[son[y]][j][1]); g[i+j][0]=min(g[i+j][0],f[x][i][0]+f[son[y]][j][1]+1); g[i+j][1]=min(g[i+j][1],f[x][i][1]+f[son[y]][j][0]+1); } memcpy(f[x],g,sizeof(f[x])); siz[x]+=siz[son[y]]; } } int main(){ scanf("%d",&n); for (int i=1,a,b;i<n;i++) scanf("%d%d",&a,&b),add(a,b),add(b,a); if (n==2) return puts("1"),0; for (int i=1;i<=n;i++) isl[i]=(in[i]==1); memset(f,63,sizeof(f)); for (int i=1;i<=n;i++) if (in[i]!=1){ dfs(i,0),printf("%d ",min(f[i][siz[i]>>1][0],f[i][siz[i]>>1][1])); break; } // for (int i=1;i<=n;i++) printf("%d %d ",i,siz[i]); return 0; }