[bzoj4472][树形DP] Salesman

题目

原地址

解说

刚看完这道题感觉还是挺乱的,可能那时候脑子不太清醒,一度觉得自己又要重拾Tarjan了。当然最后还是发觉应该用树形DP。

(以下dp[u]代表以u为根的包括自己在内的子树的最大利润,bool g[u]表示u及其子树的方案数是否唯一,唯一则为0,否则为1,t[u]代表u的次数,v[u]代表u的价值)

计算最大利润确实挺简单。有点像之前做过的空调教室,但是多了次数限制和负数,但这不难处理。计算u的时候因为每个儿子在走完之后必须返回u来回到根节点,因此我们只能对儿子的dp值进行排序,选取前t[u]-1个,并且遇到负数立即停止因为接下来选的负数只能使总价值变小。

那么怎么处理方案是否唯一呢?

我们开一个bool数组g表示u及其子树的方案数是否唯一。显然,只有以下3种情况下方案数不唯一:

某个取得的儿子dp值为0(选不选都可以)

某个取得的儿子g值为1(在这颗子树中有不同的路径)

下个未选的儿子和最后选择的儿子f值相同(可以替换)(我写的时候忽略了这一点但是还是A了,大约是数据太弱了)

那么就从根开始递归一遍就可以了哦,最后看dp[1]和g[1]就可以了。

(部分实在想不上来的做法参考了DZN大佬的,谢谢啦~)

[bzoj4472][树形DP] Salesman

 代码

[bzoj4472][树形DP] Salesman
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=100000+5,Inf=2147483647;
 4 inline int read(){
 5    int s=0,w=1;
 6    char ch=getchar();
 7    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
 8    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
 9    return s*w;
10 }
11 int n,head[maxn],tot,v[maxn],t[maxn],dp[maxn];
12 bool g[maxn];
13 struct node{
14     int to,next;
15 }e[2*maxn];
16 void Add(int a,int b){
17     e[tot].to=b;
18     e[tot].next=head[a];
19     head[a]=tot;
20     tot++;
21 }
22 void dfs(int x,int fa){
23     priority_queue<pair<int,int> > q;//按照dp值大小排序 
24     for(int i=head[x];i;i=e[i].next){
25         int v=e[i].to;
26         if(v==fa) continue;
27         dfs(v,x);
28         q.push(make_pair(dp[v],v));
29     }
30     int num=0,sum=0,judge=0;
31     while(!q.empty()&&num<t[x]-1){
32         if(q.top().first<0) break;//出现拖后腿的立即停止 
33         if(q.top().first==0){//有0说明方案不为1,
34         //且0后面要么是0要么是负的,都无法做贡献,直接退 
35             judge=1;
36             break;
37         }
38         sum+=q.top().first;
39         if(g[q.top().second]==1) judge=1;
40         q.pop();
41         num++;
42     }
43     dp[x]=sum+v[x];
44     g[x]=judge;
45 }
46 int main(){
47     tot=1;
48     t[1]=Inf;//注意自己家可以走无数次 
49     n=read();
50     for(int i=2;i<=n;i++) v[i]=read();
51     for(int i=2;i<=n;i++) t[i]=read();
52     for(int i=1;i<=n-1;i++){
53         int x,y;
54         x=read(); y=read();
55         Add(x,y);
56         Add(y,x);
57     }
58     dfs(1,0);
59     printf("%d\n",dp[1]);
60     if(g[1]) printf("solution is not unique");
61     else printf("solution is unique");
62     return 0;
63 }
View Code

幸甚至哉,歌以咏志。

上一篇:JDBC编程(上)


下一篇:PostgreSQL中的整除截断