好久没更新了,还是要总结一下
第一次参加集训队考试,拿了非集训队的第一,happy ing
主要是靠ac此题拿的分
题目大意:给出一颗n个节点的树,要给每一条边染一个1~n-1的颜色,染颜色i的代价为i,要求同一个节点连出的所有边所染颜色都互不相同,求一个为整棵树染色的方案,使得代价之和尽量小。
贪心明显是有后效性的,考虑设计f[i][j]表示i这棵子树,i到根选择j这种颜色,此子树的最优值,明显f[i][j]=min sigma(f[son][k]),其中k互不相等,且不等于j,观察转移,我们实际是为每个son这一个颜色且颜色不相同,使sigma最小,这就相当于是一个最优匹配的过程,(可以联想到ltc的部分搜索+匹配以及mt的noip模拟的一道树形dp题也是可以用匹配转移),由于每次我们只需对儿子进行两次找增广轨(因为颜色可能与父亲相同),所以均摊是n^3,考场上大部分人可能写的是状压(随机情况下期望较好),所以速度都比较慢,我的程序跑的应该是最快的吧
#include <cstdio>
#include <cstdlib>
#include <cstring>
const int oo=1073741819;
int lx[151],ly[151],_lx[151],_ly[151],slack[151],b[151][151],f[151][151],g[151],_g[151],rt[151],w[151],ry[151],n,d;
int pow[151][151],ans[151][151][151];
bool vx[151],vy[151],v[151];
int min(int x,int y) {return (x<y) ? x : y;}
int max(int x,int y) {return (x>y) ? x : y;}
int km(int x)
{
int i,ne,tmp;
if (vx[x]) return 0;
vx[x]=1;
for (i=1;i<=n-1;i++) {
ne=i;
if (v[ne]) continue;
tmp=lx[x]+ly[ne]-f[x][ne];
if (!vy[ne] && !tmp) {
vy[ne]=1;
if ( (!g[ne]) || (km(g[ne])) ) {
g[ne]=x;return 1;
}
}
else slack[ne]=min(slack[ne],tmp);
}
return 0;
}
int mysoul(int x)
{
int sum=0,i,j,ne,na;
for (i=1;i<=b[x][0];i++) {
ne=b[x][i];
if (ne==rt[x]) continue;
memset(slack,127,sizeof(slack));memset(vx,0,sizeof(vx));memset(vy,0,sizeof(vy));
for (;!km(ne);) {
d=oo;
for (j=1;j<=n-1;j++) if (!vy[j]) d=min(d,slack[j]);
for (j=1;j<=b[x][j];j++) {
na=b[x][j];
if (vx[na]) lx[na]-=d;
}
for (j=1;j<=n-1;j++) if (vy[j]) ly[j]+=d;else slack[j]-=d;
memset(vx,0,sizeof(vx));memset(vy,0,sizeof(vy));
}
}
for (i=1;i<=n-1;i++)
if (g[i]) sum+=lx[g[i]]+ly[i];
return sum;
}
void origin(int x)
{
int i,ne,j;
for (i=1;i<=n-1;i++) ly[i]=0,g[i]=0;
for (i=1;i<=b[x][0];i++) {
ne=b[x][i];lx[ne]=-oo;
for (j=1;j<=n-1;j++) lx[ne]=max(lx[ne],f[ne][j]);
}
}
void cover(int x)
{
int i,ne;
for (i=1;i<=n-1;i++) _ly[i]=ly[i],_g[i]=g[i];
for (i=1;i<=b[x][0];i++) {ne=b[x][i];_lx[ne]=lx[ne];}
}
void recover(int x)
{
int i,ne;
for (i=1;i<=n-1;i++) ly[i]=_ly[i],g[i]=_g[i];
for (i=1;i<=b[x][0];i++) {ne=b[x][i];lx[ne]=_lx[ne];}
}
void getans(int x,int i)
{
int j;
for (j=1;j<=n-1;j++)
if (g[j]) ans[x][i][g[j]]=j;
}
void dfs(int x)
{
int i,ne,tot,j;
for (i=1;i<=b[x][0];i++) {
ne=b[x][i];
if (ne!=rt[x]) rt[ne]=x,ry[ne]=pow[x][i],dfs(ne);
}
origin(x);
tot=mysoul(x);
cover(x);
for (i=1;i<=n-1;i++) {
if (g[i]==0) {f[x][i]=tot-i,getans(x,i);continue ;}
v[i]=1;
memset(slack,127,sizeof(slack));memset(vx,0,sizeof(vx));memset(vy,0,sizeof(vy));
for (;!km(g[i]);) {
d=oo;
for (j=1;j<=n-1;j++) if (!vy[j]) d=min(d,slack[j]);
for (j=1;j<=b[x][j];j++) {
ne=b[x][j];
if (vx[ne]) lx[ne]-=d;
}
for (j=1;j<=n-1;j++) if (vy[j]) ly[j]+=d;else slack[j]-=d;
memset(vx,0,sizeof(vx));memset(vy,0,sizeof(vy));
}
d=0;
for (j=1;j<=n-1;j++)
if (g[j] && !v[j]) {
d+=lx[g[j]]+ly[j];
ans[x][i][g[j]]=j;
}
f[x][i]=d-i;v[i]=0;
recover(x);
}
}
void link(int x,int y,int i)
{
b[x][++b[x][0]]=y,b[y][++b[y][0]]=x;
pow[x][b[x][0]]=i,pow[y][b[y][0]]=i;
}
void getout(int x,int y)
{
int i,ne;
for (i=1;i<=b[x][0];i++) {
ne=b[x][i];
if (ne!=rt[x]) {
w[ry[ne]]=ans[x][y][ne];
getout(ne,ans[x][y][ne]);
}
}
}
void init()
{
int i,x,y,tot;
scanf("%d\n",&n);
for (i=1;i<=n-1;i++) {
scanf("%d%d\n",&x,&y);
link(x,y,i);
}
for (i=1;i<=b[1][0];i++)
rt[b[1][i]]=1,ry[b[1][i]]=pow[1][i],dfs(b[1][i]);
origin(1);
tot=mysoul(1);
printf("%d\n",-tot);
for (i=1;i<=n-1;i++)
if (g[i]) w[ry[g[i]]]=i,getout(g[i],i);
for (i=1;i<=n-1;i++) printf("%d ",w[i]);
}
int main()
{
freopen("painting.in","r",stdin);
freopen("2painting.out","w",stdout);
init();
return 0;
}