题意:给一个n,接着输入n个数,表示n个点的值,接着输入n-1条边形成一个生成树
问最大有多少个点的集合使得该集合内的所有点都满足如下:对于集合内点大小相邻的两个点,该两点之间经过的所有点的大小都小于该两点
eg 7
3 30 350 100 200 300 400
1 2 2 3 3 4 4 5 5 6 6 7
该无向图可表示为1——2——3——4——5——6——7
取点6对于集合(3-7)来说,正好比他大的点为点3,且他们之间的所有点的
大小都小于该两点,满足条件
同理取该集合内的其他点也满足条件
所有这个集合所有点满足条件,所以最大值为5(计算其他集合发现没有更大的集合满足上述条件)
分析:该题可以转换为,建有向图,对于一条边点值小的指向大的边,求由一
个点出发可以走过的最多的点数
如样例图为1->2->3<-4->5->6->7 当取点4时能经过5个点
注意:用深搜写要手动扩栈,并且要有C++交,不然会RE暴栈,用bfs写不会
代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #pragma comment(linker,"/STACK:102400000,102400000") //手动扩栈 using namespace std; const int maxn = 5e5+5; int E = 0; int w[maxn]; int num[maxn]; int pnt[maxn*2],nxt[maxn*2],head[maxn*2]; void add(int u,int v) //邻接表 { nxt[E]=head[u]; pnt[E]=v; head[u]=E++; } void dfs(int u){ //深搜 num[u]++; for(int i=head[u];i!=-1;i=nxt[i]){ int v=pnt[i]; if(!num[v]) dfs(v); num[u]+=num[v]; //加上邻接点走过的个数 } } int main() { int n; while(scanf("%d",&n)!=EOF) { E=0; memset(head,-1,sizeof(head)); memset(num,0,sizeof(num)); for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); if(w[u]<w[v]) add(u,v); else add(v,u); } int ans=0; for(int i=1;i<=n;i++){ if(!num[i]) dfs(i); ans=max(ans,num[i]); //求最大值 } printf("%d\n",ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-08 10:41:45