题意:
在一棵树上有n个节点,n-1条边,每条边有距离。
每个节点会给你原来是男孩还是女孩。
问最少要交换多少次,使得每个女孩都能被保护到。
保护到的条件是女孩和最近的男孩的距离小于等于D
思路:
首先要求一下mp[i][j],就是任意两个点之间的距离
这个方法随意都可以的。
因为男孩只能放在树上,所以行为树,列也为树
这样每次求出的cnt就是每次最多要有多少个男的在指定的树上
这时候就需要剪枝了
剪枝就是
1、如果x+h()>boy 需要男生数超过总的男生数 return
2、每次遍历一遍当前的ans[i],sum=Σnode[ans[i]],sum是已经确定有多少个男生不用换,如果x-sum>cnt,x-sum是最好的情况需要换几次,如果比cnt大就返回。
代码:
#include"stdio.h"
#include"algorithm"
#include"string.h"
#include"iostream"
#include"queue"
#include"map"
#include"vector"
#include"string"
using namespace std;
#define N 55*55*(55+55)
#define RN 55*55
#define CN 55+55
int haha,mp[55][55],node[55];
int boy;
struct DLX
{
int n,m,C;
int U[N],D[N],L[N],R[N],Row[N],Col[N];
int H[RN],S[CN],cnt,ans[RN];
void init(int _n,int _m)
{
n=_n;
m=_m;
for(int i=0; i<=m; i++)
{
S[i]=0;
U[i]=D[i]=i;
L[i]=(i==0?m:i-1);
R[i]=(i==m?0:i+1);
}
C=m;
for(int i=1; i<=n; i++) H[i]=-1;
}
void link(int x,int y)
{
C++;
Row[C]=x;
Col[C]=y;
S[y]++;
U[C]=U[y];
D[C]=y;
D[U[y]]=C;
U[y]=C;
if(H[x]==-1) H[x]=L[C]=R[C]=C;
else
{
L[C]=L[H[x]];
R[C]=H[x];
R[L[H[x]]]=C;
L[H[x]]=C;
}
}
void del(int x)
{
for(int i=D[x]; i!=x; i=D[i])
{
R[L[i]]=R[i];
L[R[i]]=L[i];
}
}
void rec(int x)
{
for(int i=U[x]; i!=x; i=U[i])
{
R[L[i]]=i;
L[R[i]]=i;
}
}
int used[CN];
int h()
{
int sum=0;
for(int i=R[0]; i!=0; i=R[i]) used[i]=0;
for(int i=R[0]; i!=0; i=R[i])
{
if(used[i]==0)
{
sum++;
used[i]=1;
for(int j=D[i]; j!=i; j=D[j]) for(int k=R[j]; k!=j; k=R[k]) used[Col[k]]=1;
}
}
return sum;
}
void dance(int x)
{
if(x+h()>boy ) return ;
int sum=0;
for(int i=0; i<x; i++) sum+=node[ans[i]];
if(x-sum>=cnt) return ;
if(R[0]==0)
{
cnt=min(cnt,x-sum);
return ;
}
int now=R[0];
for(int i=R[0]; i!=0; i=R[i])
{
if(S[i]<S[now])
now=i;
}
for(int i=D[now]; i!=now; i=D[i])
{
ans[x]=Row[i];
del(i);
for(int j=R[i]; j!=i; j=R[j]) del(j);
dance(x+1);
for(int j=L[i]; j!=i; j=L[j]) rec(j);
rec(i);
}
return ;
}
} dlx;
struct noe
{
int to,next,v;
} edge[8000];
struct Tarjan
{
int tot,n,m;
int f[4000],x[4000],y[4000],z[4000],dis[4000],vis[4000],head[4000];
void add_edge(int a,int b,int c)
{
edge[tot].to=b;
edge[tot].next=head[a];
edge[tot].v=c;
head[a]=tot++;
}
int fin(int x)
{
if (f[x]!=x)
return f[x]=fin(f[x]);
return f[x];
}
void tarjan(int w)
{
int i;
vis[w]=1;
f[w]=w;
for (i=1; i<=m; i++)
{
if (vis[y[i]] && x[i]==w) z[i]=fin(y[i]);
if (vis[x[i]] && y[i]==w) z[i]=fin(x[i]);
}
for (i=head[w]; i!=-1; i=edge[i].next)
if (vis[edge[i].to]==0)
{
dis[edge[i].to]=dis[w]+edge[i].v;
tarjan(edge[i].to);
f[edge[i].to]=w;
}
}
void make(int _n)
{
n=_n;
m=n*n;
tot=0;
memset(head,-1,sizeof(head));
for(int i=1; i<n; i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c);
add_edge(b,a,c);
}
memset(z,0,sizeof(z));
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
int tep=(i-1)*n+j;
x[tep]=i;
y[tep]=j;
}
}
dis[1]=0;
memset(vis,0,sizeof(vis));
tarjan(1);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
int tep=(i-1)*n+j;
mp[i][j]=mp[j][i]=dis[x[tep]]+dis[y[tep]]-2*dis[z[tep]];
}
}
}
} go;
int main()
{
int t,cas=1;
cin>>t;
while(t--)
{
int n,d;
scanf("%d%d",&n,&d);
boy=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&node[i]);
if(node[i]==1) boy++;
}
go.make(n);
dlx.init(n,n);
for(int j=1; j<=n; j++)
{
for(int k=1; k<=n; k++)
{
if(mp[j][k]<=d) dlx.link(j,k);
}
}
dlx.cnt=999;
dlx.dance(0);
printf("Case #%d: %d\n",cas++,dlx.cnt==999?-1:dlx.cnt);
}
return 0;
}