[poj-3253]Fence Repair 題解

題目傳送門
題意解析:題目就是告訴我們n塊木板,每塊木板都有一個長度。然後一開始有一塊木板,這塊木板的長度是n塊木板之和,然後每次都要把一塊木板鋸開,每次的費用就是木板的長度,最後問題得到一開始n塊木板的費用最小值。


My opinion:一開始看到這題時一臉懵逼的,完全不會,怎麼鋸?難道dfs,因爲你不知道這塊木板該鋸成什麼大小。又想了一會,突然發現這題跟合併果子差不多,只不過這題時倒着來的,我們可以合併這些木板,跟鋸開這些木板的費用是一樣的,這樣就好辦了,我們每次找出最小的兩個值合併就ok了。
總結:
1、輸入,建堆。
2、每次找出兩個合併,並加在答案上。
3、輸出。


用了左偏樹的代碼:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define Clear(a,x) memset(a,x,sizeof(a))
#define ll long long
#define INF 2000000000
#define eps 1e-8
using namespace std;
ll read(){
    ll x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:f,ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=20005;
struct node{
    int l,r,dis;
    ll key;
}a[maxn<<1];
int n,now;
ll ans;
int merge(int A,int B){
    if (A==0) return B;
    if (B==0) return A;
    if (a[A].key>a[B].key)
        swap(A,B);
    a[A].r=merge(a[A].r,B);
    if (a[a[A].r].dis>a[a[A].l].dis)
        swap(a[A].l,a[A].r);
    a[A].dis=a[a[A].r].dis+1;
    return A;
}
int top(){
    int l=a[now].l,r=a[now].r;
    a[now].l=0,a[now].r=0;
    ll sum=a[now].key;
    now=merge(l,r);
    return sum;
}
int main(){
    n=read();
    now=1;ans=0;
    rep(i,1,n){
        a[i].key=read();
        a[i].l=a[i].r=0;
        a[i].dis=0;
        if (i!=1) now=merge(now,i);
    }
    int len=n;
    rep(i,1,len-1){
        int x=top(),y=top();
        ans+=x+y;
        a[++n].key=x+y;
        a[n].l=0,a[n].r=0;
        a[n].dis=0;
        now=merge(now,n);
    }
    printf("%lld\n",ans);
    return 0;
}

因爲dalao把這題放在了左偏樹專題上,所以我用了左偏樹,事實上兩個用兩個隊列也可以解決(可能吧,反正合並果子可以)

發佈了48 篇原創文章 · 獲贊 15 · 訪問量 8750
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章