topcoder 12543 DeerInZooDivOne


给出一个 \(n\) 个节点的树,求出两个极大的不相交的同构联通子图的大小.

\(1\leq n\leq 50\)

首先要保证不相交,考虑断掉一条边,两个联通子图在两边,再考虑在断开的两个树中找到根节点 \(r_1\)\(r_2\),然后树形 \(dp\) ,考虑 \(dp(x,y)\) 为第一个树上选节点 \(x\) ,第二个树上选节点 \(y\) 的最大联通子图大小,问题就出在树形 \(dp\) 的转移,要考虑儿子节点之间的 \(dp\) 匹配,这个问题可以用最小费用流 .

考虑 \(S\) 向每一个 \(x\) 的儿子节点连边 \((1,0)\)\(y\) 的每个儿子节点向 \(T\) 连边 \((1,0)\)\(x\) 的儿子节点 \(x'\)\(y\) 的儿子节点连边 \((1,-dp(x',y'))\)

得到的代价取反 \(+1\) 即为 \(dp(x,y)\) .

时间复杂度 : \(O(n^6)\)

空间复杂度 : \(O(n^2)\)

code

#include
using namespace std;
const int N=55;
class MaxFlow{
public:
	class edge{public:int to,nxt,cap,w;}e[(N*N)<<1];
	int cnt=0;
	int hd[N],dis[N],flw[N],pe[N],px[N];
	bool vis[N];
	queueQ;
	inline void init(){cnt=0;memset(hd,-1,sizeof(hd));}
	inline void ae(int u,int v,int cap,int w){
		e[cnt]=(edge){v,hd[u],cap,w};hd[u]=cnt++;
		e[cnt]=(edge){u,hd[v],0,-w};hd[v]=cnt++;
	}
	bool spfa(int s,int t){
		memset(dis,0x3f3f3f3f,sizeof(dis));
		memset(flw,0x3f3f3f3f,sizeof(flw));
		memset(vis,0,sizeof(vis));
		px[t]=-1;dis[s]=0;vis[s]=true;Q.push(s);
		while(!Q.empty()){
			int x=Q.front();vis[x]=false;Q.pop();
			for(int i=hd[x];i!=-1;i=e[i].nxt){
				if(e[i].cap&&dis[e[i].to]>dis[x]+e[i].w){
					dis[e[i].to]=dis[x]+e[i].w;
					flw[e[i].to]=min(flw[x],e[i].cap);
					px[e[i].to]=x;pe[e[i].to]=i;
					if(!vis[e[i].to])vis[e[i].to]=true,Q.push(e[i].to);
				}
			}
		}
		return px[t]!=-1;
	}
	int mcf(int s,int t){
		int res=0;
		while(spfa(s,t)){
			res+=dis[t]*flw[t];
			for(int x=t;x!=s;x=px[x])e[pe[x]].cap-=flw[t],e[pe[x]^1].cap+=flw[t];
		}
		return -res;
	}
}F;
class DeerInZooDivOne{
public:
	int n;
	vectorg[N],e[N];
	vectorvec[2],dvec[2];
	bool col[N];
	int dp[N][N];
	void dfs(int x,int fa,int c){
		col[x]=c;vec[c].push_back(x);
		for(auto to:e[x]){
			if(to==fa)continue;
			dfs(to,x,c);
		}
	}
	void dfs(int x,int fa){
		for(auto to:e[x]){
			if(to==fa||col[to]!=col[x])continue;
			dfs(to,x);
			g[x].push_back(to);
		}
		dvec[col[x]].push_back(x);
	}
	int solve(int x,int y){
		for(int i=0;ia,vectorb){
		n=(int)a.size()+1;
		for(int i=0;i