Hdu 5325 2015多校对抗赛三

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5325

Crazy Bobo

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 1305    Accepted Submission(s): 399


Problem Description
Bobo has a tree,whose vertices are conveniently labeled by 1,2,...,n.Each node has a weight  wi . All the weights are distrinct.
A set with m nodes  v1,v2,...,vm  is a Bobo Set if:
- The subgraph of his tree induced by this set is connected.
- After we sort these nodes in set by their weights in ascending order,we get  u1,u2,...,um ,(that is, wui<wui+1  for i from 1 to m-1).For any node  x  in the path from  ui  to  ui+1 (excluding  ui  and  ui+1 ),should satisfy  wx<wui .
Your task is to find the maximum size of Bobo Set in a given tree.
 

Input
The input consists of several tests. For each tests:
The first line contains a integer n ( 1n500000 ). Then following a line contains n integers  w1,w2,...,wn  ( 1wi109 ,all the  wi  is distrinct).Each of the following n-1 lines contain 2 integers  ai  and  bi ,denoting an edge between vertices  ai  and  bi  ( 1ai,bin ).
The sum of n is not bigger than 800000.
 

Output
For each test output one line contains a integer,denoting the maximum size of Bobo Set.
 

Sample Input
  
  
7 3 30 350 100 200 300 400 1 2 2 3 3 4 4 5 5 6 6 7
 

Sample Output
  
  
5
 

Author
ZSTU
 

Source
 
题目意思:一颗树上有n个节点,由n-1条边连接,每个节点有个权值。
定义一个集合:这个集合内的点按权值小到大排序,要求相连两点路径上的所有点(不包括这两端点)的权值比起始点权值小。
求最大集合的大小。
分析:
对于相连三点:     小  中  大  (小到中,中到大,此序列满足要求)
小  大  中 (小到中,路径上有个节点大,不满足要求)
中  小  大  (小到中,满足,中到大,中间有小的节点,但是仍然小于起始节点中,满足)
有以上三种情况,小中大表示点的权值。可见,如果我们把树弄出有向边,那么一定是相对小权值指向相对大权值。
那么,就可以从权最小的节点往外搜,直到外围都是大点。按照上述方式建边,权最小的点的入度一定为0。
最后取个最大值就是答案。
当树是一条链的时候,dfs递归深度很大,需手动扩栈。并且需要记忆化搜索才不会T,所谓记忆化搜索就是标记保存搜索的点的结果,下次碰到此点就不往下搜了。
貌似bfs会T,虽然不会有栈问题,bfs没有记忆搜索。

还有另外一种相对的方法,从最大值节点出发,回到最小值节点,最后取最大值也是答案。但是,建边的话就应该大边指向小边了。
就是从大值节点往小值节点宽搜,一步一步把节点数加到小值节点上面。

#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
int w[500001];
int rudu[500001];
int mark[500001];
vector <int> edge[500001];
void dfs(int u,int &cnt){
    int len=edge[u].size();
    for(int i=0;i<len;i++){
        int v=edge[u][i];
        if(mark[v]!=0)cnt+=mark[v];//记忆化搜索
        else{
            int tmp=cnt;
            dfs(v,++cnt);
            mark[v]=cnt-tmp;
        }
    }
}
void bfs(int u,int &cnt){//没有记忆化搜索
    queue <int> que;
    que.push(u);
    while(!que.empty()){
        int u=que.front();que.pop();
        int len=edge[u].size();
        for(int i=0;i<len;i++){
            int v=edge[u][i];
                que.push(v);
                cnt+=1;
        }
    }
}
int main(){
    int n;
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++){
            edge[i].clear();
            rudu[i]=0;
            mark[i]=0;
            scanf("%d",&w[i]);
        }
        for(int i=1;i<n;i++){
            int a,b;scanf("%d%d",&a,&b);
            if(w[a]>w[b]){edge[b].push_back(a);rudu[a]++;}
            else {edge[a].push_back(b);rudu[b]++;}
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            int tmp=1;
            if(rudu[i]==0){
                dfs(i,tmp);mark[i]=tmp;
//                bfs(i,tmp);//TLE
                ans=max(ans,tmp);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
int w[500001];
int rudu[500001];
int cnt[500001];
vector <int> edge[500001];
int main(){
    int n;
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++){
            edge[i].clear();
            rudu[i]=0;
            cnt[i]=0;
            scanf("%d",&w[i]);
        }
        queue <int> que;
        for(int i=1;i<n;i++){
            int a,b;scanf("%d%d",&a,&b);
            if(w[a]<w[b])swap(a,b);
            edge[a].push_back(b);
            rudu[b]++;
        }
        for(int i=1;i<=n;i++)if(rudu[i]==0)que.push(i);
        while(!que.empty()){
            int u=que.front();que.pop();
            int len=edge[u].size();
            for(int i=0;i<len;i++){
                int v=edge[u][i];
                cnt[v]+=cnt[u]+1;
                rudu[v]--;
                if(rudu[v]==0)que.push(v);
            }
        }
        int tot=0;
        for(int i=1;i<=n;i++){
            tot=max(tot,cnt[i]);
        }
        printf("%d\n",tot+1);
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值