• [洛谷P4438] HNOI2018 道路


    问题描述

    W 国的交通呈一棵树的形状。W 国一共有n - 1个城市和n个乡村,其中城市从1到n - 1 编号,乡村从1到n编号,且1号城市是首都。道路都是单向的,本题中我们只考虑从乡村通往首都的道路网络。对于每一个城市,恰有一条公路和一条铁路通向这座城市。对于城市i, 通向该城市的道路(公路或铁路)的起点,要么是一个乡村,要么是一个编号比ii大的城市。 没有道路通向任何乡村。除了首都以外,从任何城市或乡村出发只有一条道路;首都没有往 外的道路。从任何乡村出发,沿着唯一往外的道路走,总可以到达首都。

    W 国的国王小 W 获得了一笔资金,他决定用这笔资金来改善交通。由于资金有限,小 W 只能翻修n - 1条道路。小 W 决定对每个城市翻修恰好一条通向它的道路,即从公路和铁 路中选择一条并进行翻修。小 W 希望从乡村通向城市可以尽可能地便利,于是根据人口调 查的数据,小 W 对每个乡村制定了三个参数,编号为ii的乡村的三个参数是ai,bi和ci。假设 从编号为i的乡村走到首都一共需要经过x条未翻修的公路与y条未翻修的铁路,那么该乡村 的不便利值为

    [c_i cdot (a_i + x) cdot (b_i + y) ]

    在给定的翻修方案下,每个乡村的不便利值相加的和为该翻修方案的不便利值。 翻修n - 1条道路有很多方案,其中不便利值最小的方案称为最优翻修方案,小 W 自然 希望找到最优翻修方案,请你帮助他求出这个最优翻修方案的不便利值。

    输入格式

    第一行为正整数n。

    接下来n - 1行,每行描述一个城市。其中第i行包含两个数si,ti。si表示通向第i座城市 的公路的起点,ti表示通向第i座城市的铁路的起点。如果si > 0,那么存在一条从第si座城 市通往第i座城市的公路,否则存在一条从第-si个乡村通往第i座城市的公路;ti类似地,如 果ti >,那么存在一条从第ti座城市通往第i座城市的铁路,否则存在一条从第-ti个乡村通 往第i座城市的铁路。

    接下来n行,每行描述一个乡村。其中第i行包含三个数ai,bi,ci,其意义如题面所示。

    输出格式

    输出一行一个整数,表示最优翻修方案的不便利值。

    样例输入

    6
    2 3
    4 5
    -1 -2
    -3 -4
    -5 -6
    1 2 3
    1 3 2
    2 1 3
    2 3 1
    3 1 2
    3 2 1

    样例输出

    54

    解析

    由题目的意思,最后构成的树有这些特征:叶节点都是乡村;每个城市只有两个儿子,且一个是公路,一个是铁路。考虑阶段为当前到了哪个点。描述一个状态则需要知道经过了多少公路,多少铁路。所以,我们设计状态如下:

    (f[x][l][r])表示当前在x点,经过了l条未翻修的公路、r条未翻修的铁路的最小不方便值。考虑到正着并不好推,我们尝试着倒着推。每个点只会被两个子节点更新,且一个子节点是经过公路,一个是经过铁路。不难得到,我们有如下方程:

    [f[x][l][r]=min(f[ls[x]][l+1][r],f[rs[x]][l][r+1]) ]

    当x为叶节点时,由题中的式子,我们可以得到如下初始状态:

    [f[x][l][r]=c_i*(a_i+l)*(b_i+r) ]

    在dfs时,为了优化时间,我们需要记下当前最多会经过多少条没有翻修的公路和铁路。但是,这并不能解决空间的问题。可以发现,每次结束递归的点此后都不会再调用,所以我们可以每次给一个点一个编号,结束递归回收利用编号,就可以做到优化空间了。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define int long long
    #define N 40002
    using namespace std;
    int n,i,a[N],b[N],c[N],ls[N],rs[N],f[102][42][42],dfn[N];
    int read()
    {
    	char c=getchar();
    	int w=0,f=1;
    	while(c<'0'||c>'9'){
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w*f;
    }
    void dfs(int x,int l,int r,int tim)
    {
    	dfn[x]=tim;
    	if(x>=n){
    		for(int i=0;i<=l;i++){
    			for(int j=0;j<=r;j++) f[dfn[x]][i][j]=c[x]*(a[x]+i)*(b[x]+j);
    		}
    		return;
    	}
    	dfs(ls[x],l+1,r,tim+1);
    	dfs(rs[x],l,r+1,tim+2);
    	int pl=dfn[ls[x]],pr=dfn[rs[x]];
    	for(int i=0;i<=l;i++){
    		for(int j=0;j<=r;j++){
    			f[dfn[x]][i][j]=min(f[pl][i][j]+f[pr][i][j+1],f[pl][i+1][j]+f[pr][i][j]);
    		}
    	}
    }
    signed main()
    {
    	n=read();
    	for(i=1;i<=n-1;i++){
    		ls[i]=read(),rs[i]=read();
    		if(ls[i]<0) ls[i]=-ls[i]+n-1;
    		if(rs[i]<0) rs[i]=-rs[i]+n-1;
    	}
    	for(i=n;i<=2*n-1;i++) a[i]=read(),b[i]=read(),c[i]=read();
    	memset(f,0x3f,sizeof(f));
    	dfs(1,0,0,1);
    	printf("%lld
    ",f[1][0][0]);
    	return 0;
    }
    

    反思

    • 没有看到路径长度小于等于40的条件,导致半天没有设计状态的思路。
    • 正难则反,老是想着从上到下,没有想过可以从叶节点出发倒推得到答案。
  • 相关阅读:
    Ext.Net 1.2.0_利用 Ext.Net 自定义 GridPanel Ajax 控件
    ASP.NET_0404_ASP.NET 重定向:页面传值
    程序设计_洗牌程序
    表单/验证表单——千万不要做一个只会拖控件、“照猫画虎”、copy/paste 程序员
    ASP.NET_0204_ASP.NET 重定向:如何将用户重定向到另一页
    Oracle 11g R1(11.1) Joins表连接
    隐藏 iframe 技术——Ajax 时代一个重要的环节
    Ext.Net 1.2.0_改变 Ext.Net.GridPanel 某行或某列的式样
    数据结构冒泡排序和直接插入排序
    XMLHttpRequest——Ajax 时代的到来
  • 原文地址:https://www.cnblogs.com/LSlzf/p/11723390.html
Copyright © 2020-2023  润新知