【清澄竞技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;}
- 【清澄竞技4.7】painting
- 清澄 1000 1001 1002
- 清澄A1025. 字符串对比
- 清澄A1026. 字符统计
- 清澄A1028. 选择计算
- 清澄A1030. 球队排名
- 清澄A1033. 绘制图形
- 清澄A1036. 分解质因数
- 清澄A1040. Cantor表
- 清澄A1051. DNA序列
- 竞技游戏
- 清澄OJ 1001: 01序列
- 清澄A1052-数的读法
- 清澄A1223. 画圈圈(范浩强)
- 清澄A1023. 瓷砖铺放
- 清澄A1032. 画三角形2
- 清澄A1042. 矩形面积交
- 竞技游戏的未来
- x264耗时分析范例【转载】
- 字符设备驱动之流水灯——FS2410
- android系统数据库
- silverlight样式1
- struts2 批量添加
- 【清澄竞技4.7】painting
- Quartus 警告分析
- c++中的const与指针
- x264中的NAL流程
- 51CTO一个不错的资源网
- struts2 拦截器
- Eclipse开发Android程序如何在手机上运行
- uboot代码下载
- struts2 用Spring实现Ioc