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