loj #2510. 「AHOI / HNOI2018」道路

#2510. 「AHOI / HNOI2018」道路

題目描述

W 國的交通呈一棵樹的形狀。W 國一共有 n1 個城市和 nnn 個鄉村,其中城市從 111 到 n1 編號,鄉村從 111 到 nnn 編號,且 111 號城市是首都。道路都是單向的,本題中咱們只考慮從鄉村通往首都的道路網絡。對於每個城市,恰有一條公路和一條鐵路通向這座城市。對於城市 iii,通向該城市的道路(公路或鐵路)的起點,要麼是一個鄉村,要麼是一個編號比 iii 大的城市。沒有道路通向任何鄉村。除了首都之外,從任何城市或鄉村出發只有一條道路;首都沒有往 外的道路。從任何鄉村出發,沿着惟一往外的道路走,總能夠到達首都。html

W 國的國王小 W 得到了一筆資金,他決定用這筆資金來改善交通。因爲資金有限,小 W 只能翻修 n1 條道路。小 W 決定對每一個城市翻修剛好一條通向它的道路,即從公路和鐵路中選擇一條並進行翻修。小 W 但願從鄉村通向城市能夠儘量地便利,因而根據人口調查的數據,小 W 對每一個鄉村制定了三個參數,編號爲 iii 的鄉村的三個參數是 aia_iai​​,bib_ibi​​ 和 cic_ici​​。假設從編號爲 iii 的鄉村走到首都一共須要通過 xxx 條未翻修的公路與 yyy 條未翻修的鐵路,那麼該鄉村的不便利值爲node

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

在給定的翻修方案下,每一個鄉村的不便利值相加的和爲該翻修方案的不便利值。ios

翻修 n1 條道路有不少方案,其中不便利值最小的方案稱爲最優翻修方案,小 W 天然但願找到最優翻修方案,請你幫助他求出這個最優翻修方案的不便利值。網絡

輸入格式

第一行爲正整數 nnn。 接下來 n1 行,每行描述一個城市。其中第 iii 行包含兩個數 si,tis_i, t_isi​​,ti​​。sis_isi​​ 表示通向第 iii 座城市的公路的起點,tit_iti​​ 表示通向第 iii 座城市的鐵路的起點。若是 si>0s_i > 0si​​>0,那麼存在一條從第 sis_isi​​ 座城市通往第 iii 座城市的公路,不然存在一條從第 −si-s_isi​​ 個鄉村通往第 iii 座城市的公路;tit_iti​​ 相似地,若是 ti>0t_i > 0ti​​>0,那麼存在一條從第 tit_iti​​ 座城市通往第 iii 座城市的鐵路,不然存在一條從第 −ti-t_iti​​ 個鄉村通往第 iii 座城市的鐵路。ide

接下來 nnn 行,每行描述一個鄉村。其中第 iii 行包含三個數 ai,bi,cia_i, b_i, c_iai​​,bi​​,ci​​,其意義如題面所示。ui

輸出格式

輸出一行一個整數,表示最優翻修方案的不便利值。atom

樣例

樣例輸入 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

樣例解釋 1

樣例.png

如圖所示,咱們分別用藍色、黃色節點表示城市、鄉村;用綠色、紅色箭頭分別表示公路、鐵路;用加粗箭頭表示翻修的道路。spa

一種不便利值等於 545454 的方法是:翻修通往城市 222 和城市 555 的鐵路,以及通往其餘城市的公路。用→\rightarrow→和⇒\Rightarrow⇒表示公路和鐵路,用→和⇒表示翻修的公路和鐵路,那麼:code

  • 編號爲 111 的鄉村到達首都的路線爲:131,通過 000 條未翻修公路和 111 條未翻修鐵路,代價爲 3×(1+0)×(2+1)=93 \times (1 + 0) \times (2 + 1) = 93×(1+0)×(2+1)=9;
  • 編號爲 222 的鄉村到達首都的路線爲:231,通過 000 條未翻修公路和 222 條未翻修鐵路,代價爲 2×(1+0)×(3+2)=102 \times (1 + 0) \times (3 + 2) = 102×(1+0)×(3+2)=10;
  • 編號爲 333 的鄉村到達首都的路線爲:3421,通過 111 條未翻修公路和 000 條未翻修鐵路,代價爲 3×(2+1)×(1+0)=93 \times (2 + 1) \times (1 + 0) = 93×(2+1)×(1+0)=9;
  • 編號爲 444 的鄉村到達首都的路線爲:4421,通過 111 條未翻修公路和 111 條未翻修鐵路,代價爲 1×(2+1)×(3+1)=121 \times (2 + 1) \times (3 + 1) = 121×(2+1)×(3+1)=12;
  • 編號爲 555 的鄉村到達首都的路線爲:5521,通過 111 條未翻修公路和 000 條未翻修鐵路,代價爲 2×(3+1)×(1+0)=82 \times (3 + 1) \times (1 + 0) = 82×(3+1)×(1+0)=8;
  • 編號爲 666 的鄉村到達首都的路線爲:6521,通過 000 條未翻修公路和 000 條未翻修鐵路,代價爲 1×(3+0)×(2+0)=61 \times (3 + 0) \times (2 + 0) = 61×(3+0)×(2+0)=6;

總的不便利值爲 9+10+9+12+8+6=549 + 10 + 9 + 12 + 8 + 6 = 549+10+9+12+8+6=54。能夠證實這是本數據的最優解。htm

樣例輸入 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

樣例解釋 2

在這個樣例中,顯然應該翻修全部公路。

樣例輸入 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

數據範圍與提示

共 202020 組數據,編號爲 120。

對於編號 ≤4\le 44 的數據,n≤20n \le 20n20;

對於編號爲 58 的數據,ai,bi,ci5n50;

對於編號爲 912 的數據,n≤2000n \le 2000n2000;

對於全部的數據,n≤20000n \le 20000n20000,1≤ai,bi≤601 \le a_i, b_i \le 601ai​​,bi​​60,1≤ci≤1091 \le c_i \le 10^91ci​​109​​,si,tis_i, t_isi​​,ti​​ 是 [n,1](i,n1] 內的整數,任意鄉村能夠經過不超過 404040 條道路到達首都。

 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 50
using namespace std;
int map[maxn][maxn];
int n,m,head[maxn],num,a[maxn],b[maxn],c[maxn],son[maxn][2];
struct node{int to,pre,v,w;}e[maxn*maxn];
void Insert(int from,int to,int w){
    e[++num].to=to;
    e[num].w=w;
    e[num].pre=head[from];
    head[from]=num;
}
int cnt[maxn][2];
long long ans=1000000000000000;
void dfs(int x,int cnt0,int cnt1){
    if(x<=n){
        cnt[x][0]=cnt0;
        cnt[x][1]=cnt1;
    }
    for(int i=head[x];i;i=e[i].pre){
        int to=e[i].to;
        if(e[i].w==0&&e[i].v==0)dfs(to,cnt0+1,cnt1);
        else if(e[i].w==1&&e[i].v==0)dfs(to,cnt0,cnt1+1);
        else dfs(to,cnt0,cnt1);
    }
}
long long count(int sta){
    for(int i=1;i<n;i++){
        if(sta&(1<<(i-1))){//連向右孩子的邊被重建
            e[map[i+n][son[i+n][0]]].v=0;
            e[map[i+n][son[i+n][1]]].v=1;
        }
        else {//連向左孩子的邊被重建
            e[map[i+n][son[i+n][0]]].v=1;
            e[map[i+n][son[i+n][1]]].v=0;
        }
    }
    dfs(n+1,0,0);
    long long res=0;
    for(int i=1;i<=n;i++){
        res+=1LL*c[i]*(a[i]+cnt[i][0])*(b[i]+cnt[i][1]);
    }
    return res;
}
int main(){
    scanf("%d",&n);
    m=n+n-1;
    int x,y;
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        if(x<0)x=-x;
        else x+=n;
        if(y<0)y=-y;
        else y+=n;
        son[i+n][0]=x;son[i+n][1]=y;
        Insert(i+n,x,0);map[i+n][x]=map[x][i+n]=num;
        Insert(i+n,y,1);map[i+n][y]=map[y][i+n]=num;
    }
    for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i],&b[i],&c[i]);
    for(int i=0;i<(1<<(n-1));i++){
        ans=min(ans,count(i));
    }
    cout<<ans<<endl;
    return 0;
}
20分 暴力
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 20010
using namespace std;
int n,son[maxn][2];
long long f[maxn][50][50];
struct node{long long x,y,z;}a[maxn];
long long dfs(int x,int p,int q){
    if(x>=n){
        int now=x-n+1;
        return a[now].z*(a[now].x+p)*(a[now].y+q);
    }
    if(f[x][p][q]!=f[n+1][41][41])return f[x][p][q];
    return f[x][p][q]=min(dfs(son[x][0],p,q)+dfs(son[x][1],p,q+1),dfs(son[x][1],p,q)+dfs(son[x][0],p+1,q));
}
int main(){
    int x,y;
    scanf("%d",&n);
    memset(f,127,sizeof(f));
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        if(x<0)x=-x+n-1;
        if(y<0)y=-y+n-1;
        son[i][0]=x;
        son[i][1]=y;
    }
    for(int i=1;i<=n;i++)
        scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].z);
    printf("%lld\n",dfs(1,0,0));
    return 0;
}
100分 樹形dp
相關文章
相關標籤/搜索