链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3684
题意:题中给出一个树,结点是城市,路径有长度和炸毁需要的武器单位数,,X单位的武器能同时炸毁所有X单位以下的路径。问需要多少单位的武器能使所有边疆城市和中心城市不联通。
思路:中心城市就是整棵树的根(到所有城市中的最长距离最短的城市),树的根一定在树的直径上。两次DFS找到树的直径,枚举找到根(姿势不够优美,更好的方式是树形DP)。然后进行二分枚举炸弹单位数判断联通性即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 10005
#define INF 1<<25
#define MAX 0x7fffffff
typedef long long ll;
using namespace std;
struct Edge
{
int v;
long long w,a;
int next;
} edge[maxn*2];
int head[maxn],vis[maxn],leaf[maxn];
long long dist[maxn],way[maxn],rc[maxn];
int now=0,A=0,s=0,top=0;
long long ttt=0;
int add_edge(int u,int v,int w,int a)
{
edge[top].v=v;
edge[top].w=w;
edge[top].a=a;
edge[top].next=head[u];
head[u]=top++;
edge[top].v=u;
edge[top].w=w;
edge[top].a=a;
edge[top].next=head[v];
head[v]=top++;
return 0;
}
int ans=0;
int dfs(int x)
{
if(ans>s)
s=ans;
vis[x]=1;
for(int i=head[x]; i!=-1; i=edge[i].next)
{
int v=edge[i].v;
if(!vis[v])
{
ans+=edge[i].w;
dist[v]=ans;
dfs(v);
ans-=edge[i].w;
}
}
return 0;
}
int dfs3(int x,int root)
{
vis[x]=1;
rc[now++]=x;
if(ans>ttt)
{
ttt=ans;
A=now;
for(int i=0; i<now; i++)
way[i]=rc[i];
}
for(int i=head[x]; i!=-1; i=edge[i].next)
{
int v=edge[i].v;
if(!vis[v])
{
ans+=edge[i].w;
dist[v]=ans;
dfs3(v,root);
ans-=edge[i].w;
now--;
}
}
return 0;
}
int dfs2(int x,int bomb)
{
vis[x]=1;
for(int i=head[x]; i!=-1; i=edge[i].next)
{
int v=edge[i].v;
if(!vis[v]&&edge[i].a>bomb)
{
dfs2(v,bomb);
}
}
return 0;
}
int main()
{
int t;
while(scanf("%d",&t)!=EOF)
{
top=0,ttt=0,now=0,A=0,ans=0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
for(int i=1; i<t; i++)
{
int a,b;
long long c;
int d;
scanf("%d%d%lld%d",&a,&b,&c,&d);
add_edge(a,b,c,d);
}
dfs(1);
int L=-1,d=0;
for(int i=1; i<=t; i++)
if(dist[i]>d)
{
L=i;
d=dist[i];
}
memset(vis,0,sizeof(vis));
ans=0;
dfs3(L,L);
int R=-1;
long long ss=-1;
for(int i=0; i<A; i++)
{
ans=0;
s=0;
memset(vis,0,sizeof(vis));
dfs(way[i]);
if(s<ss||ss==-1)
{
ss=s;
R=way[i];
}
}
int T=0;
for(int i=1; i<=t; i++)
{
if(edge[head[i]].next==-1)
{
leaf[T++]=i;
}
}
int l=0,r=100000005;
int mid;
while(r>l)
{
memset(vis,0,sizeof(vis));
mid=(r+l)/2;
dfs2(R,mid);
int flag=0;
for(int i=0; i<T; i++)
{
if(!vis[leaf[i]])
flag++;
}
if(flag==T)
r=mid;
else l=mid+1;
}
printf("%d\n",(r+l)/2);
}
return 0;
}