[BZOJ4472]-树形&贪心

来源:互联网 发布:淘宝优站报名入口 编辑:程序博客网 时间:2024/06/05 09:14

last update at 2017.11.6

1.规范了板式
2.修改了部分口胡的语句


说在前面

这个水题写了我一个白天= =
就因为建边忘了建双向边,以为所有给的边都是father->son的
简直*了狗(狗:woc关我啥事)


题意:

给你一棵含有n个节点的树,每个节点有权值(可正可负),并且每个节点有路过次数上限。仅在第一次路过某个节点后,获得该节点的权值。现问从1号节点出发,在树上随便跑(可以不进入某些节点)后能获得的最大收益,并输出方案是否唯一。
若唯一,输出solution is unique
else,输出solution is not unique
方案唯一是指:至少有两个方案可以达到该权值,并且此两方案路过的节点不至少有一个点不同。

输入

第一行一个整数:n,代表总节点数。
第二行n-1个整数,代表第二到第n个点的权值
第三行n-1个整数,代表第二到第n各节点最大可路过次数
接下来n-1行,每行两个整数,代表此两节点之间有一条边。
9
-3 -4 2 4 -2 3 4 6
4 4 2 2 2 2 2 2
1 2
1 3
1 4
2 5
2 6
3 7
4 8
4 9
数据保证每个节点路过次数不小于二,并且从1可以到达任意一点,即整个图是联通的,不是森林。1号节点进入次数不限,权值为0.

输出

9
solution is unique


解法

一开始看到这个题可能会想到树形背包
然而这道题因为不确定选点的个数,因此背包的容积是不确定的,因此不能用背包做。
看到这里,请读者仔细思考一下该题正解:
·
·
·
·
·
·
·
·
·
·
·
如果还没想出来–>请回头看一下本文标题
.
.
.
.
.
.
.
.
.
.
.
可以发现,节点的权值有正有负,由于我们路过点的次数有限,那么我们肯定是尽量的把正权值的点选完

于是思路出来了:
递归处理每个子节点,然后把已经处理好的子节点的最优解从大到小排序,如果正权值已经选完,或者选的节点到达上限,就退出循环。

那么如何确定解是不是唯一呢?
在把子树的最大收益计算出来之后,是排了一遍 续....续1s!序的。如果当前选择的最后一个节点,和第一个me没选的节点收益一样,那么方案不唯一。如果me选中的节点中有收益为0的,那么方案也不唯一。


下面是自带大常数的代码:

其中,pro[i]代表的是点i的初始利润
dp数组为处理之后,路过改点获得的最大收益
isnotuni==is not unique
tim[i]表示i点最大可经过次数
其余的应该都能懂 ~

/* *************************************************************    Problem: 4472    User: Izumihanako    Language: C++    Result: Accepted    Time:336 ms    Memory:4340 kb*************************************************************** */#include<cstdio>#include<algorithm>#include<cstring>#include<vector>using namespace std;int n,pro[100001],tim[100001],head[100001],tw=0;int dp[100001],isnotuni[100001];struct node{    int pre,to;}w[200001];int comp(const pair<int,int > &a,const pair<int,int > &b){    if(a.first<b.first)  return 0;    return 1;}void In(int t1,int t2){    w[++tw].pre=head[t1];    w[tw].to=t2;    head[t1]=tw;}void work(int u,int f){    vector< pair<int,int> > Ve;    Ve.clear();    for(int i=head[u];i;i=w[i].pre){        int v=w[i].to;        if(v==f)    continue;        work(v,u);        Ve.push_back(make_pair<int,int>(dp[v],v));    }    sort( Ve.begin(), Ve.end(), comp);    int i=0,R=Ve.size()-1;    for(;i<=R&&i+2<=tim[u]&&Ve[i].first>=0;i++){        isnotuni[u]|=isnotuni[Ve[i].second];        dp[u]+=Ve[i].first;    }    if(i>0&&i!=Ve.size())        isnotuni[u]|=(Ve[i-1].first==Ve[i].first ? 1 : 0);    if(i>0&&Ve[i-1].first==0)        isnotuni[u]=1;    dp[u]+=pro[u];}inline int read(){    int data=0,w=1; char ch=0;    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();    if(ch=='-') w=-1,ch=getchar();    while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();    return data*w;}int main(){    int t1,t2;    scanf("%d",&n);    for(int i=2;i<=n;i++)        pro[i]=read();    for(int i=2;i<=n;i++)        tim[i]=read();    tim[1]=0x3f3f3f3f;    for(int i=2;i<=n;i++){        t1=read();t2=read();        In(t1,t2);        In(t2,t1);    }    work(1,0);    printf("%d\n",dp[1]);    if(isnotuni[1]==1)        printf("solution is not unique");    else        printf("solution is unique");    return 0;}
原创粉丝点击