zoukankan      html  css  js  c++  java
  • [JSOI2015]salesman「树形DP+贪心」

    题目描述

    懒得复制了

    思路分析

    • 题目说的非常磨叽。我们先来读题,这很重要。首先任意两个城镇之间都只有唯一的路线,说明这是一棵树。停留一次就饱和,说明每个点的点权只能获得一次,即使经过多次。还有一个很重要的一点,这是一个巡回,也就是说最后要再次回到根节点,是一个来回,每个节点只要向其子节点走,就一定还会再回来,耗费一次停留次数。(最后一点必须get到)

    • 而停留次数只会在上面提到的过程中消耗,不可能出现跑回父节点再跑回来的可能,显然这样是白白耗费了次数而没有任何收益

    • 到这里大体的模型就已经出来了。每个点的停留次数 (-1)(因为最初到达这个节点耗费了一次停留次数)就是最多的到达其子节点的次数(这里有的题解说是子树,显然是有缺陷的)。到达子节点后就可以继续像这样递归处理。

    • 然后根据贪心思想,对所有以子节点为根的收益排序(用一个优先队列就够了),最多选 该节点的停留次数 (-1) 个 。因为有负数,所以不一定要选满

    • 最后就是判断是否有多解了,因为题目说了与路径无关,所以只需考虑收益的大小,只有两种情况:

      1. 以某个节点为根的收益大小为0,可选可不选
      2. 再排好序选完以后,没有选的子节点中存在和以及选了的相同的,可以2选1

    (Code)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<map>
    #define R register
    #define N 500010
    using namespace std;
    inline int read(){
    	int x = 0,f = 1;
    	char ch = getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,v[N],c[N],f[N],head[N];
    bool flag;
    struct edge{
    	int to,next;
    }e[N<<1];
    int len;
    void addedge(int u,int v){
    	e[++len].to = v;
    	e[len].next = head[u];
    	head[u] = len;
    }
    int dfs(int u,int fa){
    	priority_queue<int>q;
    	map<int,int>vis;//用于多解的情况2
    	f[u] = v[u];
    	for(R int i = head[u];i;i = e[i].next){
    		int v = e[i].to;
    		if(v==fa)continue;
    		int tmp = dfs(v,u);
    		q.push(tmp);
    	}
    	int cnt = 0,last = 0;
    	while(!q.empty()){
    		if(cnt==c[u]-1)break;
    		int x = q.top();q.pop();
    		if(x<0)break;
    		last = x;
    		f[u] += x;
    		vis[x] = 1;
    		cnt++;
    	}
    	if(!q.empty()){
    		int x = q.top();
    		if(vis[x])flag = 1;//多解的情况2
    	}
    	if(f[u]==0)flag = 1;//多解的情况1
    	return f[u];
    }
    int main(){
    	n = read();
    	for(R int i = 2;i <= n;i++)v[i] = read();
    	for(R int i = 2;i <= n;i++)c[i] = read();
    	for(R int i = 1;i < n;i++){
    		int x = read(),y = read();
    		addedge(x,y),addedge(y,x);
    	}
    	c[1] = 0x3f3f3f3f;//根节点随便停留
    	dfs(1,0);
    	printf("%d
    ",f[1]);
    	if(flag)puts("solution is not unique");
    	else puts("solution is unique");
    	return 0;
    }
    
    
  • 相关阅读:
    洛谷P3799 妖梦拼木棒
    bzoj1008 [HNOI2008]越狱
    洛谷P3414 SAC#1
    洛谷P1078 文化之旅
    bzoj1053 [HAOI2007]反素数ant
    洛谷P1588 丢失的牛
    bzoj1085 [SCOI2005]骑士精神
    noip2016 蚯蚓
    noip2016 换教室
    html笔记03:表单
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13803984.html
Copyright © 2011-2022 走看看