Highest Tower Gym - 101550H(建圖,思路)

在這裏插入圖片描述
題意: n個矩形,要求使得上面矩形寬度嚴格小於下面矩形,問能夠得到的最大高度。

思路:
很巧妙的思路。

  1. 首先題目保證一定有解。考慮將每個矩形的邊(u,v)設置雙向邊u->v與v->u,u->v代表選擇u爲寬,v爲高。
  2. 那麼可以建出一張圖,這個圖可以分出很多連通分量,不同連通分量意味着每個邊都是不同的,那麼可以在兩個連通分量內分別堆成最高的矩形,然後將兩者合併,結果仍然最優。所以對連通分量可以分別考慮
  3. 假設連通分量內有n個點,m條邊,代表可以堆m個矩形,最多有n個寬度可以用。要滿足題意,必須使得每個點出度不大於1,則有 m=n 或者 m=n-1。
  4. 這實際意味着這張圖是樹或者基環樹,然後我們要將每個邊定向,選擇相應的寬高。
  5. 當這張圖爲基環圖時,每個點都要分一個度數作爲出度(當做寬),剩下度數作爲高,所以每個點的貢獻爲 (deg[x]1)val[x](deg[x]-1)*val[x](度數不作爲出度就得作爲入度)。
  6. 當這張圖爲樹的時候,此時有一個節點的出度爲0,我們將這個出度爲0的點連到任意其他點,就可以獲得這個點的值(此點值作爲高),我們可以貪心的選擇最大的值。
  7. m<n1m<n-1的時候,圖不連通。當m>nm>n時,要堆mm個矩形卻只有nn種寬,不合理。本題巧就巧在保證 都能用上。記得寫過堆積木的題(三維堆箱子求高),那個題範圍比較小可以直接DP。本題2e5,同時加上了巧妙的限制,所以可以用這種建圖的方法解決。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;
typedef long long ll;
const int maxn = 1e6 + 7;
map<int,int>mp;
int cnt,flag,mx;
int vis[maxn],val[maxn];
int head[maxn],nex[maxn],to[maxn],deg[maxn],tot;
ll ans;

void add(int x,int y) {
    if(!mp[x]) mp[x] = ++cnt;
    if(!mp[y]) mp[y] = ++cnt;
    val[mp[x]] = x;val[mp[y]] = y;
    x = mp[x];y = mp[y];
    deg[x]++;
    to[++tot] = y;
    nex[tot] = head[x];
    head[x] = tot;
}

void dfs(int x) {
    if(vis[x]) return;
    vis[x] = 1;
    mx = max(mx,val[x]);
    ans += 1ll * (deg[x] - 1) * val[x];
    flag += (deg[x] - 2);
    for(int i = head[x];i;i = nex[i]) {
        dfs(to[i]);
    }
}

int main() {
    int n;scanf("%d",&n);
    for(int i = 1;i <= n;i++) {
        int x,y;scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    for(int i = 1;i <= cnt;i++) {
        if(vis[i]) continue;
        flag = mx = 0;
        dfs(i);
        if(flag < 0) ans += mx;
    }
    printf("%lld\n",ans);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章