【GDOI2022PJD2T2 网页浏览】题解
D2T2 网页浏览
题目
我们在上网时,从一个网页上的链接打开另一个网页有两种方式,一个是直接替换正在浏览的页面,另一个是在新标签页中打开。如果善用这两种打开方式,是可以节省一些操作的。
今天 Zayin 需要浏览 \(n\) 个网页,其中有且仅有一个网页是保存在本地可以点击打开的,其他 \(n ? 1\) 个网页都是需要从某个页面的链接里打开的。因此,这 \(n\) 个网页的链接关系可以用一棵 \(n\) 个节点的有根树表示。
一开始,浏览器里什么标签页也没有,Zayin 可以点击根节点代表的网页,打开第一个标签页,接下来,Zayin 可以做如下的事情:
- 从当前浏览的网页所含有的链接里选择一个打开,直接替换当前的网页;
- 从当前浏览的网页所含有的链接里选择一个,在新标签页中打开;
- 点击“返回”,当前网页返回被其替换的网页,该操作只能用于“替换打开”的网页;
- 关闭当前网页。
Zayin 可以自行决定浏览顺序。求 Zayin 从空浏览器开始,到最后浏览完全部 \(n\) 个网页并全部关闭回到空浏览器的状态,最少需要多少步操作。
思路
对于任意一个节点,假设其有 \(m\) 个儿子,我们让其中 \(m-1\) 个儿子实行新建标签页操作,最后一个儿子实行直接替换操作。
如果 \(m=0\),也就是说这个点是叶子节点,就直接实行删除操作。
显然,每个节点的打开都需要一个操作。
而每个叶子节点都要无中生有,多实行一个操作。
所以答案为树的节点个数+叶子节点的个数。
代码
#include
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。
对于这种题目,我们最重要的是分析。
分析在什么时候是最优的,例如替换有时比新建更优。因为替换后只需关闭一次,而新建则要关闭很多次。
下次遇到类似题目要学会分析每个操作的代价。