计蒜客 17417 Highest Tower(思维+图论)

题解:

实际上一个可行解即选取长和宽的一个,使得最后每一组选第一维的数值都不同

在此基础上,使得另一维的和最大。

然后建立图论模型

对于每一个方块,在a和b之间连边。

对于选择的方案,如果选择a->b,那么就是以a为底,b为高

所以最后的图一定要满足所有点的出度为1(出度为2就有重复了)

基于这个我们发现只有两种情况。

1、图中含有环,实际上所有边的方向都是固定的,答案就是每个点的入度*每个点的值加起来。

2、图中不含环(树的结构),那么实际上可以选取一个点为根,根的答案可以额外计算。所以就选取树中值最大的那个点为根即可。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
using namespace std;
const int maxn = 5e5 + 100;
vector<int> G[maxn];
map<int, int> M;
long long m, N, Max, ans;
int vis[maxn], v[maxn];
void dfs(int x){
    if(vis[x]) return;
    vis[x] = 1;
    m += G[x].size(); N++; Max = max(Max, (long long)v[x]);
    ans += (G[x].size()-1)*v[x];
    for(auto to : G[x]) dfs(to);
}
int n, x, y, tot;
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d %d", &x, &y);
        if(!M[x]){
            M[x] = ++tot;
            v[tot] = x;
        }
        if(!M[y]){
            M[y] = ++tot;
            v[tot] = y;
        }
        G[M[x]].push_back(M[y]);
        G[M[y]].push_back(M[x]);
    }
    memset(vis, 0,   sizeof(vis));
    for(int i = 1; i <= tot; i++){
        if(!vis[i]) {
            N = 0;
            m = 0;
            Max = 0;
            dfs(i);
            if(m/2 == N-1) ans += Max;
        }
    }
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/Saurus/p/7637349.html