您的位置:首页 > 其它

POJ 1741 树形dp

2016-03-10 16:03 330 查看
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn = 2E5 + 10;
const int Maxm = 1E5 + 10;
const int INF = 0x3f3f3f3f;
int N, K, first[Maxm], x, y, z, Next[Maxm], v[Maxm], w[Maxm], cnt, res, q[Maxn], fa[Maxn], p[Maxn], del[Maxn], size[Maxn];
void add(int x, int y, int z)
{
v[cnt] = y, w[cnt] = z, Next[cnt] = first[x], first[x] = cnt++;
}
int findroot(int cur)
{
int i, j, x, rear = 0, Max, min = INF, root;
q[rear ++] = cur, fa[cur] = 0;
for (i = 0; i < rear; i ++)
{
x = q[i];
for (j = first[x]; j != -1; j = Next[j])
if (!del[v[j]] && v[j] != fa[x])
q[rear ++] = v[j], fa[v[j]] = x;
}
for (i = rear - 1; i >= 0; i --)
{
x = q[i];
size[x] = 1, Max = 0;
for (j = first[x]; j != -1; j = Next[j])
if (!del[v[j]] && v[j] != fa[x])
size[x] += size[v[j]], Max = max(Max, size[v[j]]);
Max = max(Max, rear - size[x]);
if (Max < min)
min = Max, root = x;
}
return root;
}
int deal(int s, int t)
{
int i, rear = t, ans = 0;
for (i = s; i <= t; i ++)
{
while (rear >= s && p[rear] + p[i] > K)
-- rear;
ans += rear - s + 1;
}
return ans;
}
void renew(int s, int cur, int d)
{
int i, j, x, rear = 0;
q[rear ++] = cur, fa[cur] = 0, p[s] = d;
for (i = 0; i < rear; i ++)
{
x = q[i];
for (j = first[x]; j != -1; j = Next[j])
if (!del[v[j]] && v[j] != fa[x])
p[s + rear] = p[s + i] + w[j], q[rear ++] = v[j], fa[v[j]] = x;
}
sort(p + s, p + s + rear);
}
int dfs(int s, int cur, int d)
{
int i, root, n, tot = 1;
root = findroot(cur);
del[root] = 1;
for (i = first[root]; i != -1; i = Next[i])
if (!del[v[i]])
{
n = dfs(s + tot, v[i], w[i]);
res -= deal(s + tot, s + tot + n - 1);
tot += n;
}
p[s] = 0;
sort(p + s, p + s + tot);
res += deal(s, s + tot - 1) - 1;
del[root] = 0;
renew(s, cur, d);
return tot;
}
int main(int argc, char const *argv[])
{
while (~scanf("%d%d", &N, &K) && N + K)
{
cnt = 0; res = 0;
memset(first, -1, sizeof(first));
for (int i = 1; i < N; i++)
scanf("%d%d%d", &x, &y, &z), add(x, y, z), add(y, x, z);
dfs(0, 1, 0);
printf("%d\n", res >> 1);
}
return 0;
}


 恩,楼教主的八题之一,需要优化的树形dp,具体思路有漆子超的《分治算法在树的路径问题中的应用》这篇论文。

题解思路来自:http://blog.sina.com.cn/s/blog_6d5aa19a0100o73m.html

//__________________________________________________________

对于一棵有根树, 树中满足要求的一个数对所对应的一条路径,必然是以下两种情况之一:

1、经过根节点

2、不经过根节点,也就是说在根节点的一棵子树中

对于情况2,可以递归求解,下面主要来考虑情况1。

设X为满足i<j且Depth[i]+Depth[j]<=K的数对(i,j)的个数

设Y为满足i<j,Depth[i]+Depth[j]<=K且Belong[i]=Belong[j]数对(i,j)的个数

那么我们要统计的量便等于X-Y

求X、Y的过程均可以转化为以下问题:

已知A[1],A[2],...A[m],求满足i<j且A[i]+A[j]<=K的数对(i,j)的个数

对于这个问题,我们先将A从小到大排序。

设B[i]表示满足A[i]+A[p]<=K的最大的p(若不存在则为0)。我们的任务便转化为求出A所对应的B数组。那么,若B[i]>i,那么i对答案的贡献为B[i]-i。

显然,随着i的增大,B[i]的值是不会增大的。利用这个性质,我们可以在线性的时间内求出B数组,从而得到答案。

综上,设递归最大层数为L,因为每一层的时间复杂度均为“瓶颈”——排序的时间复杂度O(NlogN),所以总的时间复杂度为O(L*NlogN)

//_________________________________________________________________________________________________________
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: