【清澄竞技4.7】painting

来源:互联网 发布:adobe audition mac版 编辑:程序博客网 时间:2024/04/28 15:40

好久没更新了,还是要总结一下

第一次参加集训队考试,拿了非集训队的第一,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;}


原创粉丝点击