一道题18
Posted Blue233333
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一道题18相关的知识,希望对你有一定的参考价值。
$n leq 2000$的树,问从原点出发把每条边走至少一次再回到原点最少代价,有边权。其中可以使用$k$次传送门,始末位置不限,一次代价为$c$。
如果没有$k$的话直接每条边走两次。由于传送一次相当于一条链不用走,搞出来应该是求$k$条边不相交链的最大权和(相交的话,相交部分走了两次,相当于没优化过)。
树形dp,$f(i,j,0/1)$--子树$i$,已经有$j$条链完整覆盖了的最大权和,0/1表示是否能够伸一条不完整的链往上(以便在某个祖先处和另一条不完整链拼接)。分若干种情况转移。
背包容量严格等于子树大小时,这样的复杂度是$n^2$的。
1 //#include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 //#include<time.h> 5 //#include<complex> 6 //#include<set> 7 //#include<queue> 8 //#include<vector> 9 #include<algorithm> 10 #include<stdlib.h> 11 using namespace std; 12 13 #define LL long long 14 int qread() 15 { 16 char c; int s=0,f=1; while ((c=getchar())<‘0‘ || c>‘9‘) (c==‘-‘) && (f=-1); 17 do s=s*10+c-‘0‘; while ((c=getchar())>=‘0‘ && c<=‘9‘); return s*f; 18 } 19 20 //Pay attention to ‘-‘ , LL and double of qread!!!! 21 22 int n,C,K; 23 #define maxn 4011 24 struct Edge{int to,next,v;}edge[maxn<<1]; int first[maxn],le=2; 25 void in(int x,int y,int v) {Edge &e=edge[le]; e.to=y; e.v=v; e.next=first[x]; first[x]=le++;} 26 void insert(int x,int y,int v) {in(x,y,v); in(y,x,v);} 27 28 int f[maxn][maxn][2],g[maxn][2],size[maxn]; 29 void dp(int x,int fa) 30 { 31 memset(f[x],0,sizeof(f[x])); 32 size[x]=0; 33 for (int i=first[x];i;i=edge[i].next) 34 { 35 Edge &e=edge[i]; if (e.to==fa) continue; 36 dp(e.to,x); 37 for (int j=size[x]+size[e.to];~j;j--) g[j][0]=f[x][j][0],g[j][1]=f[x][j][1]; 38 for (int j=size[x];~j;j--) 39 for (int k=1;k<=size[e.to];k++) 40 g[j+k][0]=max(g[j+k][0],f[x][j][1]+f[e.to][k-1][1]+e.v); 41 for (int j=size[x];~j;j--) 42 for (int k=0;k<=size[e.to];k++) 43 g[j+k][1]=max(g[j+k][1],f[x][j][0]+f[e.to][k][1]+e.v); 44 for (int j=size[x];~j;j--) 45 for (int k=0;k<=size[e.to];k++) 46 g[j+k][1]=max(g[j+k][1],f[x][j][1]+f[e.to][k][0]); 47 for (int j=size[x];~j;j--) 48 for (int k=0;k<=size[e.to];k++) 49 g[j+k][0]=max(g[j+k][0],f[x][j][0]+f[e.to][k][0]); 50 size[x]+=size[e.to]; 51 for (int j=size[x];~j;j--) f[x][j][0]=g[j][0],f[x][j][1]=g[j][1]; 52 } 53 for (int i=0;i<=size[x];i++) f[x][i][1]=max(f[x][i][1],f[x][i][0]); 54 if (x==1) for (int i=0;i<size[x];i++) f[x][i+1][0]=max(f[x][i+1][0],f[x][i][1]); 55 size[x]++; 56 } 57 int main() 58 { 59 // freopen("mzz.in","r",stdin); 60 // freopen("mzz.out","w",stdout); 61 while (~scanf("%d",&n)) 62 { 63 K=qread(); C=qread(); le=2; memset(first,0,sizeof(first)); 64 for (int i=1,x,y,v;i<n;i++) {x=qread()+1; y=qread()+1; v=qread(); insert(x,y,v);} 65 dp(1,0); 66 int ans=0,tot=0; 67 for (int i=2;i<le;i++) tot+=edge[i].v; 68 ans=tot; 69 for (int i=0;i<=K;i++) ans=min(ans,tot-f[1][i][0]+C*i); 70 printf("%d ",ans); 71 } 72 return 0; 73 }
以上是关于一道题18的主要内容,如果未能解决你的问题,请参考以下文章
Python练习册 第 0013 题: 用 Python 写一个爬图片的程序,爬 这个链接里的日本妹子图片 :-),(http://tieba.baidu.com/p/2166231880)(代码片段