听队长说他挂完之后才发现这是一套final题,蒟蒻瑟瑟发抖......结果是只有一题想出正解,还没有A掉。。。
这道题当时没有想清楚,因为时间太少了。
我们以每一个节点为根节点进行判断。dis[u]记录侵略和占领以u为根节点的子树所需要的兵力
sum[u]记录死伤和驻守兵力
当我们到达一个节点,首先dis[u]=max(sum[u],a[u].tot)记录下到达u节点需要的兵力
假设我们现在已经有dis[u]的兵力了,那么我们肯定要优先侵占dis[v]大的子树
因为你总兵力是一致的,总损伤也是一致的,如果一个dis[v]要比sum[v]大很多的子节点放最后一个侵占
那么当前总兵力dis[u]很有可能不够,所以就要加
然而我们如果先侵占dis[v]大的节点的话,吧dis[v]小的放到最后侵占,那么这样一定是最优的
因为一个重要的性质,dis[v]>=sum[v],对我们侵占顺序产生影响的只有a[v].tot们
因为当前的总兵力dis[u]减去除v以外所有损失兵力sum[u],还无法侵占一个dis[v]最小的点的话,
那么这个总兵力dis[u]一定是不够的。
然而队长先侵占sum[v]大的也能A,不知道为什么,题解里反而写要先侵占损伤小的看似很有道理然而A不掉。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define maxl 110
#define inf 2000000001
using namespace std;
int n,cnt,cas,ans;
int dis[maxl],frm[maxl],ehead[maxl],sum[maxl];
struct node
{
int tot,w1,w2;
}a[maxl];
queue <int> q;
struct ed
{
int to,nxt;
}e[maxl*maxl*2];
struct sn{int val1,val2;};
vector <sn> son[maxl];
bool con[maxl][maxl];
bool cmp(const sn &x,const sn &y)
{
if(x.val1==y.val1)
return x.val2<y.val2;
else
return x.val1<y.val1;
}
inline void add(int u,int v)
{
e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt;
}
inline void prework()
{
int u,v;
for(int i=1;i<=n;i++)
scanf("%d%d%d",&a[i].tot,&a[i].w1,&a[i].w2);
cnt=0;
memset(ehead,0,sizeof(ehead));
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
}
void dfs(int u,int fa)
{
int v,mx=0;sn d;
sum[u]=a[u].w1+a[u].w2;
dis[u]=max(sum[u],a[u].tot);
son[u].clear();
for(int i=ehead[u];i;i=e[i].nxt)
{
v=e[i].to;
if(v!=fa)
{
dfs(v,u);
d.val2=sum[v];d.val1=dis[v];
son[u].push_back(d);
}
}
sort(son[u].begin(),son[u].end(),cmp);
int l=son[u].size(),res=0;
for(int i=l-1;i>=0;i--)
{
int nd=son[u][i].val1;
int de=son[u][i].val2;
dis[u]=max(dis[u],sum[u]+nd);
sum[u]+=de;
}
}
inline void mainwork()
{
int cur;
ans=inf;
for(int i=1;i<=n;i++)
{
memset(dis,0,sizeof(dis));
memset(sum,0,sizeof(sum));
dfs(i,0);
ans=min(dis[i],ans);
}
}
inline void print()
{
cas++;
printf("Case %d: %d\n",cas,ans);
}
int main()
{
while(~scanf("%d",&n) && n)
{
prework();
mainwork();
print();
}
return 0;
}