Description
给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.
Input
第一行 两个整数 n, k
第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)
Output
一个整数 表示最小边数量 如果不存在这样的路径 输出-1
Sample Input
4 3
0 1 1
1 2 2
1 3 4
0 1 1
1 2 2
1 3 4
Sample Output
2
第一次写点分治……要讲详细点
把所有可行解分成过当前点和不过当前点两种情况,过当前点的直接处理,不过当前点的就递归到子树做,然后一样分为过当前点和不过当前点……
然后要找个树的重心,就是把无根树建成以x为根的有根树之后,使子树的儿子个数最大值最小的x
对于这题,用t[k]表示当前子树中到根的路径权值和为k的最短边。换而言之就是权值和为k又经过最少边
然后就可以分治搞掉
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> #include<deque> #include<set> #include<map> #include<ctime> #define LL long long #define inf 0x7ffffff #define pa pair<int,int> #define pi 3.1415926535897932384626433832795028841971 #define N 200010 using namespace std; inline LL read() { LL x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,k,cnt,sum,root,ans; struct edge{ int to,next,v; }e[2*N]; int head[N]; int f[N]; int son[N]; int vis[N]; int dep[N]; int dist[N]; int t[1000010]; inline void ins(int u,int v,int w) { e[++cnt].to=v; e[cnt].v=w; e[cnt].next=head[u]; head[u]=cnt; } inline void insert(int u,int v,int w) { ins(u,v,w); ins(v,u,w); } inline void getroot(int x,int fa) { son[x]=1;f[x]=0; for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa&&!vis[e[i].to]) { getroot(e[i].to,x); son[x]+=son[e[i].to]; f[x]=max(f[x],son[e[i].to]); } f[x]=max(f[x],sum-son[x]); if (f[x]<f[root])root=x; } inline void dfs(int x,int fa) { if(dist[x]<=k)ans=min(ans,dep[x]+t[k-dist[x]]); for (int i=head[x];i;i=e[i].next) if (fa!=e[i].to&&!vis[e[i].to]) { dep[e[i].to]=dep[x]+1; dist[e[i].to]=dist[x]+e[i].v; dfs(e[i].to,x); } } inline void add(int x,int fa,int opr) { if (dist[x]<=k) { if (opr==1)t[dist[x]]=min(t[dist[x]],dep[x]); else t[dist[x]]=inf; } for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa&&!vis[e[i].to]) add(e[i].to,x,opr); } inline void work(int x) { vis[x]=1;t[0]=0; for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]) { dep[e[i].to]=1;dist[e[i].to]=e[i].v; dfs(e[i].to,0); add(e[i].to,0,1); } for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to])add(e[i].to,0,0); for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]) { root=0;sum=son[e[i].to]; getroot(e[i].to,0); work(root); } } int main() { n=read();k=read(); for (int i=1;i<=k;i++)t[i]=n; for(int i=1;i<n;i++) { int x=read()+1,y=read()+1,z=read(); insert(x,y,z); } ans=sum=f[0]=n; getroot(1,0); work(root); if (ans==n)printf("-1 "); else printf("%d ",ans); return 0; }