zoukankan      html  css  js  c++  java
  • P1272.重建道路(树形背包)

    题意:

    给出一棵树。

    询问最少断几条边,使得存在大小为P的连通块。

    题解:

    以每个点为根节点跑树上背包即可。

    时间复杂度(O(n^3))

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=200;
    int n,p;
    vector<int> g[maxn];
    
    int f[maxn][maxn][2];
    int e[maxn];
    int sz[maxn];
    //f(i,j,k)表示第i个节点所在的连通块的大小为j,且仅考虑前k个儿子
    //最多增加的道路数 
    void dfs (int x,int pre) {
    	int k=0;
    	sz[x]=1;
    	//for (int i=0;i<=n;i++) f[x][i][k]=-1e9;
    	f[x][1][1]=0;//表示x这个点单独存在,不用加任何边 
    	for (int y:g[x]) {
    		if (y==pre) continue;
    		dfs(y,x);
    		for (int i=0;i<=sz[x];i++) {
    			for (int j=1;j<=sz[y];j++) {
    				f[x][i+j][k]=max(f[x][i+j][k],f[x][i][k^1]+f[y][j][e[y]]+1);
    				f[x][i][k]=max(f[x][i][k],f[x][i][k^1]+f[y][j][e[y]]);
    			}
    		}
    		for (int i=0;i<=sz[x];i++) f[x][i][k]=max(f[x][i][k],f[x][i][k^1]);
    		k^=1;
    		sz[x]+=sz[y];
    	}
    	e[x]=(k^1);
    }
    int main () {
    	scanf("%d%d",&n,&p);
    	for (int i=2;i<=n;i++) {
    		int x,y;
    		scanf("%d%d",&x,&y);
    		g[x].push_back(y);
    		g[y].push_back(x);
    	}
    	int ans=0;
    	for (int i=1;i<=n;i++) {
    		for (int j=0;j<=n;j++) for (int k=0;k<=n;k++) for (int x=0;x<2;x++) f[j][k][x]=-1e9;
    		dfs(i,0);
    		ans=max(ans,f[i][p][e[i]]);
    	}
    	printf("%d
    ",n-1-ans);
    }
  • 相关阅读:
    django学习笔记(一)
    Python之函数进阶
    Python之函数初识
    Python之文件操作
    基础补充
    字典
    神奇的列表
    万能的字符串
    Python基础(二)
    使用paramiko进行ssh连接
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14637003.html
Copyright © 2011-2022 走看看