珠宝(GEMS)
给一棵n 个结点的树,给每个点安排一个正整数编号,使得相邻点具有不同的编号,编号的
总和尽量小。
输入文件:
第一行:n(n<=50,000)
以下n-1 行,每行两个数u,v(1<=u,v<=n),表示u 和v 有一条边
输出文件:
仅一行,为最小编号和
SAMPLE INPUT
8
1 2
1 3
1 4
1 5
5 6
5 7
5 8
SAMPLE OUTPUT
11
这道题我基本思路+骗分70分。
思路和正确的接近:
从叶节点开始,向根。叶节点尽量小。(*)
因此我想到了拓扑排序(不过因为是从叶节点开始,所以入度和初度交换了,感觉不是很科学),
节点“入度”为0的时刻即为他的编号。(这点其实是错误的,想得出反例)
第一次我用的栈维护的堆,后来因为一些自己做的测试数据有问题,因此改成了用队列维护。
结果过不了样例,我还是交了,居然70分。。(用栈的版本10分)
//=========================================================================
正确的思路:
从(*)处不同。
从(*)处想到后序遍历,因此可以想到树形DP,
引用:
看完题目,很自然地联想到树型DP,而且也不难得到状态表示方法。先根据输入的数据构造出一棵树,然后从树的叶子结点往上倒推。设F[I,J]表示以I为根的子树在I的编号为J时,可以得到的最小编号和。
状态转移方程为:F[I,J] = Min{∑F[I1, J1]} + J
其中I1表示I的一个子结点编号,J1为不同于J的一个自然数。
(这道题不能用四色定理,不知道为什么?因此J不能只开到4,开大一点20比较安全)
动规之上还必须用优化才能AC。。。。。。。。。。
//==========================================================================
骗分程序
//贪心
#include <iostream>
using std::cout;
//using std::cin;
#include <cstdio>
#include <cstdlib>
const long oo = 0x7fff0000;
struct ftv
{
long f;
long t;
};
long n;
ftv bian[100002];
long chudu[50002];
long start[50002];
long top = 0;
long cengci[50002];
long que[100002];
long l=0;long r=0;
long long tot=0;
int bigger(const void* a,const void* b)
{
ftv* aa = (ftv*) a;
ftv* bb = (ftv*) b;
long aaa = aa->f;
long bbb = bb->f;
if (aaa>bbb) return 1;
else if(aaa<bbb) return -1;
else return -1;
}
int main()
{
freopen("gems.in","r",stdin);
freopen("gems.out","w",stdout);
scanf("%ld",&n);
long t = 0;
for (long i=1;i<n;i++)
{
long u;long v;
scanf("%ld%ld",&u,&v);
t++;
bian[t].f = u;
bian[t].t = v;
t++;
bian[t].t = u;
bian[t].f = v;
chudu[bian[t].f]++;
chudu[bian[t].t]++;
}
long m = (n-1)*2;
qsort(bian+1,m,sizeof(ftv),&bigger);
for (long i=1;i<=m;i++)
{
if (start[bian[i].f]==0)
start[bian[i].f]=i;
}
for (long i=1;i<n+1;i++)
{
if (chudu[i]==1)
{
que[++r] = i;
cengci[i] = 1;
tot++;
}
}
while (l<r)
{
long now = que[++l];
chudu[now]=-1;
for (long i=start[now];i<=m;i++)
{
if (bian[i].f!=now) break;
if (chudu[bian[i].t]>1)
{
chudu[bian[i].t]--;
if (cengci[bian[i].t]<cengci[now]+1)
{
cengci[bian[i].t]=cengci[now]+1;
}
if (chudu[bian[i].t]==1)
{
tot += cengci[bian[i].t];
que[++r] = bian[i].t;
}
}
}
}
cout << tot;
return 0;
}