给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.
标签:
给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.
第一行 两个整数 n, k
第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)
一个整数 表示最小边数量 如果不存在这样的路径 输出-1
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #define N 200100 using namespace std; int tot,n,m,all,k,root,sum; int pre[N*2],v[N*2],val[N*2],now[N],size[N],ans[N],f[N]; bool vis[N]; struct data{int val,size; }d[N],da[N]; bool cmp(data a,data b) { return a.val<b.val; } int read() { int x=0; char ch; bool bo=1; while (ch=getchar(),ch<‘0‘||ch>‘9‘) if (ch==‘-‘) bo=0; while (x=x*10+ch-‘0‘,ch=getchar(),ch>=‘0‘&&ch<=‘9‘); if (!bo) return -x; return x; } void ins(int a,int b,int c) { ++tot; pre[tot]=now[a]; now[a]=tot; v[tot]=b; val[tot]=c; } void getroot(int u,int fa) { size[u]=1; f[u]=0; for (int p=now[u]; p; p=pre[p]) { int son=v[p]; if (vis[son]||son==fa) continue; getroot(son,u); size[u]+=size[son]; f[u]=max(f[u],size[son]); } f[u]=max(f[u],all-size[u]); if (f[u]<f[root]) root=u; } void getarray(int u,int fa) { for (int p=now[u]; p; p=pre[p]) { int son=v[p]; if (son==fa||vis[son]) continue; da[++sum].val=d[son].val=d[u].val+val[p]; da[sum].size=d[son].size=d[u].size+1; getarray(son,u); } } void calc(int u,int value, int f) { d[u].val=value; if (f==1) d[u].size=0; else d[u].size=1; sum=0; da[++sum].val=value; da[sum].size=d[u].size; getarray(u,0); sort(da+1,da+1+sum,cmp); for (int i=1,j=sum; i<=j; i++) { while (j>i && da[j].val+da[i].val>k) j--; for (int p=j; da[i].val+da[p].val==k ;p--)ans[da[p].size+da[i].size]+=f; } } void solve(int u) { vis[u]=1; calc(u,0,1); for (int p=now[u]; p; p=pre[p]) { int son=v[p]; if (vis[son]) continue; calc(son,val[p],-1); all=size[son]; root=0; getroot(son,0); solve(root); } } int main() { n=read(); k=read(); for (int i=1; i<n; i++) { int u=read()+1,v=read()+1,value=read(); ins(u,v,value); ins(v,u,value); } all=n; f[root=0]=n; getroot(1,0); solve(root); for (int i=1; i<n; i++) { if (ans[i]) { printf("%d\n",i); return 0; } } printf("-1\n"); return 0; }
标签:
原文地址:http://www.cnblogs.com/HQHQ/p/5469111.html