【GDOI2022PJD2T2 网页浏览】题解

D2T2 网页浏览

题目

我们在上网时,从一个网页上的链接打开另一个网页有两种方式,一个是直接替换正在浏览的页面,另一个是在新标签页中打开。如果善用这两种打开方式,是可以节省一些操作的。

今天 Zayin 需要浏览 \(n\) 个网页,其中有且仅有一个网页是保存在本地可以点击打开的,其他 \(n − 1\) 个网页都是需要从某个页面的链接里打开的。因此,这 \(n\) 个网页的链接关系可以用一棵 \(n\) 个节点的有根树表示。

一开始,浏览器里什么标签页也没有,Zayin 可以点击根节点代表的网页,打开第一个标签页,接下来,Zayin 可以做如下的事情:

  • 从当前浏览的网页所含有的链接里选择一个打开,直接替换当前的网页;
  • 从当前浏览的网页所含有的链接里选择一个,在新标签页中打开;
  • 点击“返回”,当前网页返回被其替换的网页,该操作只能用于“替换打开”的网页;
  • 关闭当前网页。

Zayin 可以自行决定浏览顺序。求 Zayin 从空浏览器开始,到最后浏览完全部 \(n\) 个网页并全部关闭回到空浏览器的状态,最少需要多少步操作。

思路

对于任意一个节点,假设其有 \(m\) 个儿子,我们让其中 \(m-1\) 个儿子实行新建标签页操作,最后一个儿子实行直接替换操作。

如果 \(m=0\),也就是说这个点是叶子节点,就直接实行删除操作。

显然,每个节点的打开都需要一个操作。

而每个叶子节点都要无中生有,多实行一个操作。

所以答案为树的节点个数+叶子节点的个数。

代码

#include<bits/stdc++.h>
using namespace std;
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'
){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x
<<3)+(ch^48);ch=getchar();}return x*f;}
#define N 200010
//#define M
//#define mo
int n, m, i, j, k, T; 
int a[N]; 

signed main()
{
//	freopen("webpage.in", "r", stdin);
//	freopen("webpage.out", "w", stdout);
	n=read(); 
	for(i=1; i<=n; ++i) 
	{
		j=read(); 
		if(j!=-1) a[j]=1; 
	}
	for(i=1; i<=n; ++i)
	 	if(a[i]!=1) ++k; 
	printf("%d", n+k); 
	return 0;
}

总结

很巧妙的思维题,考试时想不到,打了个错的dp。

对于这种题目,我们最重要的是分析。

分析在什么时候是最优的,例如替换有时比新建更优。因为替换后只需关闭一次,而新建则要关闭很多次。

下次遇到类似题目要学会分析每个操作的代价。

posted @ 2022-04-25 17:33  zhangtingxi  阅读(26)  评论(0编辑  收藏  举报