[HNOI2018]道路(DP)

题目描述

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

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

ci⋅(ai+x)⋅(bi+y)c_i \cdot (a_i + x) \cdot (b_i + y)ci(ai+x)(bi+y)

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

输入输出格式

输入格式:

第一行为正整数nnn

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

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

输出格式:

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

输入输出样例

输入样例#1: 复制
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
输出样例#1: 复制
54
输入样例#2: 复制
9 
2 -2 
3 -3 
4 -4 
5 -5 
6 -6 
7 -7 
8 -8 
-1 -9 
1 60 1 
1 60 1 
1 60 1 
1 60 1 
1 60 1 
1 60 1 
1 60 1 
1 60 1 
1 60 1
输出样例#2: 复制
548
输入样例#3: 复制
12 
2 4 
5 3 
-7 10 
11 9 
-1 6 
8 7 
-6 -10 
-9 -4
-12 -5 
-2 -3 
-8 -11 
53 26 491 
24 58 190 
17 37 356 
15 51 997 
30 19 398 
3 45 27 
52 55 838 
16 18 931 
58 24 212 
43 25 198 
54 15 172 
34 5 524
输出样例#3: 复制
5744902
 

说明

【样例解释 1】

如图所示,我们分别用蓝色、黄色节点表示城市、乡村;用绿色、红色箭头分别表示 公路、铁路;用加粗箭头表示翻修的道路。

一种不便利值等于54的方法是:翻修通往城市2和城市5的铁路,以及通往其他城市的 公路。用→和⇒表示公路和铁路,用∗→和∗⇒表示翻修的公路和铁路,那么:

编号为1的乡村到达首都的路线为:-1 ∗→ 3 ⇒ 1,经过0条未翻修公路和1条未翻修铁 路,代价为3 × (1 + 0) × (2 + 1) = 9;
编号为2的乡村到达首都的路线为:-2 ⇒ 3 ⇒ 1,经过0条未翻修公路和2条未翻修铁 路,代价为2 × (1 + 0) × (3 + 2) = 10;
编号为3的乡村到达首都的路线为:-3 ∗→ 4 → 2 ∗→ 1,经过1条未翻修公路和0条未 翻修铁路,代价为3 × (2 + 1) × (1 + 0) = 9;
编号为4的乡村到达首都的路线为:-4 ⇒ 4 → 2 ∗→ 1,经过1条未翻修公路和1条未翻 修铁路,代价为1 × (2 + 1) × (3 + 1) = 12;
编号为5的乡村到达首都的路线为:-5 → 5 ∗⇒ 2 ∗→ 1,经过1条未翻修公路和0条未 翻修铁路,代价为2 × (3 + 1) × (1 + 0) = 8;
编号为6的乡村到达首都的路线为:-6 ∗⇒ 5 ∗⇒ 2 ∗→ 1,经过0条未翻修公路和0条未翻修铁路,代价为1 × (3 + 0) × (2 + 0) = 6;

总的不便利值为9 + 10 + 9 + 12 + 8 + 6 = 54。可以证明这是本数据的最优解。

【样例解释 2】

在这个样例中,显然应该翻修所有公路。

【数据范围】 一共20组数据,编号为1 ∼ 20。 对于编号≤4\le 44 的数据,n≤20n \le 20n20
对于编号为5 ∼ 8的数据,ai,bi,ci≤5a_i,b_i,c_i \le 5ai,bi,ci5n≤50n \le 50n50
对于编号为9 ∼ 12的数据,n≤2000n \le 2000n2000
对于所有的数据,n≤20000n \le 20000n200001≤ai,bi≤601 \le a_i,b_i \le 601ai,bi601≤ci≤1091 \le c_i \le 10^91ci109si,tis_i,t_isi,ti[−n,−1]∪(i,n−1][-n,-1] \cup (i,n - 1][n,1](i,n1] 内的整数,任意乡村可以通过不超过40条道路到达首都。

本以为必有高论。

有个鬼啊!

普及DP入门题套一个废话极多的题面就往HNOI里出。

不想多说。

下面是考场程序,数据分治都没删,把数组范围改一下就A了,考场20,无语。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (register int i=l; i<=r; i++)
 4 typedef long long ll;
 5 using namespace std;
 6 
 7 const int N=40010;
 8 const ll inf=100000000000000000;
 9 int n,x,y,fa[N],w[N],l1[N],l2[N],ch[N][2],a[N],b[N],c[N];
10 ll ans,f[N>>1][41][41];
11 
12 void jud(){
13     ll res=0;
14     rep(i,0,n-1){
15         int x=0,y=0;
16         for (int t=i+n; fa[t]; t=fa[t]){
17             if (w[t]==0) x++;
18             if (w[t]==2) y++;
19         }
20         res+=1ll*c[n+i]*(a[n+i]+x)*(b[n+i]+y);
21     }
22     ans=min(ans,res);
23 }
24 
25 void dfs(int dq){
26     if (dq==n) { jud(); return; }
27     w[ch[dq][0]]^=1; dfs(dq+1); w[ch[dq][0]]^=1;
28     w[ch[dq][1]]^=1; dfs(dq+1); w[ch[dq][1]]^=1;
29 }
30 
31 void get(int x){
32     if (!ch[x][0]) return;
33     l1[ch[x][0]]=l1[x]+1; l2[ch[x][0]]=l2[x];
34     l1[ch[x][1]]=l1[x]; l2[ch[x][1]]=l2[x]+1;
35     get(ch[x][0]); get(ch[x][1]);
36 }
37 
38 ll get(int x,int i,int j){ return (ch[x][0]) ? f[x][i][j] : 1ll*c[x]*(a[x]+i)*(b[x]+j); }
39 
40 void DP(int x){
41     if (!ch[x][0]) return;
42     DP(ch[x][0]); DP(ch[x][1]);
43     rep(i,0,l1[x]) rep(j,0,l2[x])
44         f[x][i][j]=min(get(ch[x][0],i,j)+get(ch[x][1],i,j+1),get(ch[x][0],i+1,j)+get(ch[x][1],i,j));
45 }
46 
47 int main(){
48     freopen("road.in","r",stdin);
49     freopen("road.out","w",stdout);
50     scanf("%d",&n);
51     if (n<=20){
52         rep(i,1,n-1){
53             scanf("%d%d",&x,&y);
54             if (x<=0) x=-x+n-1; if (y<=0) y=-y+n-1;
55             ch[i][0]=x; ch[i][1]=y; fa[x]=fa[y]=i; w[x]=0; w[y]=2;
56         }
57         rep(i,0,n-1) scanf("%d%d%d",&a[n+i],&b[n+i],&c[n+i]);
58         ans=inf; dfs(1); printf("%lld\n",ans);
59     }else{
60         rep(i,1,n-1){
61             scanf("%d%d",&x,&y);
62             if (x<=0) x=-x+n-1; if (y<=0) y=-y+n-1;
63             ch[i][0]=x; ch[i][1]=y; fa[x]=fa[y]=i; w[x]=0; w[y]=2;
64         }
65         rep(i,0,n-1) scanf("%d%d%d",&a[n+i],&b[n+i],&c[n+i]);
66         get(1); DP(1); printf("%lld\n",f[1][0][0]);
67     }
68     return 0;
69 }

 

 

 

转载于:https://www.cnblogs.com/HocRiser/p/8854384.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值