标签:pac cin mic ima png mamicode 限制 clu line
见题:
题目简单粗暴,真的很难想。
直接从优解的角度考虑:每条路径都是从一个叶节点到另一个叶节点的,显然这样可以经过最多的点。
考虑那对于所有的叶节点来说,这l条路径,最多覆盖l*2个点(因为每条路径最多覆盖两条叶节点),这是针对于叶节点来说的,那对于其他节点呢?
我们顺着这个思路,从叶节点向上推一层,在叶节点之上的一层,最多也覆盖l*2个点,同理,往上的每一层,对答案的贡献也都是l*2,同时加上该层的点数限制。
一层一层往上推,那不就是拓扑吗?我们可以从叶节点开始跑拓扑,记录其所在层数,最后输出答案。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1010000; int n,l,link[maxn],tot,ru[maxn],ans,deep[maxn],cnt[maxn],vis[maxn],p; struct bian { int y,next; }; bian a[maxn*2]; inline void add(int x,int y) { a[++tot].y=y; a[tot].next=link[x]; link[x]=tot; } inline void topsort() { queue<int>q; for(int i=1;i<=n;i++) if(ru[i]==1) {q.push(i);vis[i]=1;} while(!q.empty()) { int x=q.front();q.pop();cnt[deep[x]]++; for(int i=link[x];i;i=a[i].next) { int y=a[i].y; if(vis[y]) continue; deep[y]=deep[x]+1; p=max(p,deep[y]); if(--ru[y]==1) {q.push(y);vis[y]=1;} } } } int main() { freopen("1.in","r",stdin); cin>>n>>l; for(int i=1;i<n;i++) { int x,y; cin>>x>>y; add(x,y);add(y,x); ru[x]++;ru[y]++; } topsort(); for(int i=0;i<=p;i++) ans+=min(2*l,cnt[i]); cout<<ans<<endl; return 0; }
这个题启示我们,O(n)时要大胆猜测结论,同时也要大胆外推,加以验证。
其实本题的思路是直接从最有解的角度出发,考虑最优解一定有用的性质,从这些性质着手反推最优解,这种思路也是找结论时常用的思路。
那本题为什么要用拓扑呢?整体看一下本题的探索思路,我们先考虑了最优路径一定从叶节点到叶节点,之后以叶节点为一层,一步步向外推,这种一层层从已知到未知,不就是拓扑的性质!
这个题启示我们:假使遇到从叶节点出发有规律可循,可以一步一步外推至最优解,这时要合理猜测,不要忘记拓扑的力量!
标签:pac cin mic ima png mamicode 限制 clu line
原文地址:https://www.cnblogs.com/gcfer/p/11193912.html