首先中心應當位於整棵樹的直徑上,先從任意點開始搜一條最長路徑,該路徑的終點必是直徑的一段,以上結論由反證可推出矛盾。再從端點開始深搜可得直徑,遍歷該路徑即可得到中心點所在。接下來以中心點爲根節點,開始DP即可。
#include <map>
#include <cstdio>
#include <memory.h>
using namespace std;
#define it map<int,road>::iterator
struct road
{
int l, p;
} t;
map<int, road> a[10001];
int pole;
int lmax;
int n;
int temp;
inline int maxlen(int length)
{
temp = lmax - length;
return length>temp?length:temp;
}
inline int minimum(int a, int b)
{
return a<b?a:b;
}
void dfs(int cur, int pre, int len)
{
bool end = true;
for(it i=a[cur].begin(); i!=a[cur].end(); ++i)
{
if(i->first != pre)
{
end = false;
dfs(i->first, cur, len+i->second.l);
}
}
if(end && len>lmax)
{
lmax = len;
pole = cur;
}
}
int stack[10000], top;
int path[10000], plen;
void dfs1(int cur, int pre, int len)
{
stack[top++] = cur;
bool end = true;
for(it i=a[cur].begin(); i!=a[cur].end(); ++i)
{
if(i->first != pre)
{
end = false;
dfs1(i->first, cur, len+i->second.l); //bug2: dfs->dfs1
}
}
if(end && len>lmax)
{
lmax = len;
pole = cur;
plen = top;
memcpy(path, stack, top*sizeof(int));
}
-- top;
}
int dfs2(int cur, int pre)
{
int min, maxmin = -1;
bool end = true;
for(it i=a[cur].begin(); i!=a[cur].end(); ++i)
{
if(i->first != pre)
{
end = false;
min = minimum(i->second.p, dfs2(i->first, cur));
if(min > maxmin)
maxmin = min;
}
}
if(end == true) return 100000000;
else return maxmin;
}
int main()
{
int ind, ind0;
while(scanf("%d", &n) != EOF)
{
for(int i=1; i<n; ++i)
{
scanf("%d%d%d%d", &ind, &ind0, &t.l, &t.p);
a[ind][ind0] = t;
a[ind0][ind] = t;
}
lmax = -1;
dfs(1, 0, 0);
lmax = -1, top=0;
dfs1(pole, 0, 0);
int middle, length=0;
int minmax = 99999999;
for(int k=1; k<plen; ++k)
{
length += a[path[k]][path[k-1]].l; //bug1: k->path[k]...
if(maxlen(length) < minmax)
{
minmax = maxlen(length);
middle = path[k];
}
}
printf("%d\n", dfs2(middle, 0));
for(int j=1; j<=n; ++j)
a[j].clear();
}
return 0;
}