Install Air Conditioning HDU - 4756(最小生成树+树形dp)

Install Air Conditioning

HDU - 4756

题意是要让n-1间宿舍和发电站相连 也就是连通嘛 最小生成树板子一套

但是还有个限制条件 就是其中有两个宿舍是不能连着的 要求所有情况中最大的那个

这是稠密图 用kruskal的时间会大大增加 所以先跑一遍prim

跑完之后对最小生成树里面的边去搜索(树形dp)我觉得dp就是搜索(虽然我菜到切不了dp题。)

so dfs的过程我也叫做树形dp咯

dp[i][j]表示i和j不相连后 这两个部分距离最小的边

代码如下

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;

const int maxn = 1e3 + 10;
const double inf = 0x3f3f3f3f3f3f;
double d[maxn][maxn], lowc[maxn], dp[maxn][maxn];
bool vis[maxn], is_tree[maxn][maxn];
int pre[maxn], head[maxn];
int cnt, n, m;
double sum, ans;

struct Point {
    double x, y;
} a[maxn];
struct Edge {
    int to, next;
} edge[maxn<<1];

inline double distan(const Point& lhs, const Point& rhs) {
    return sqrt((lhs.x - rhs.x) * (lhs.x - rhs.x) + (lhs.y - rhs.y) * (lhs.y - rhs.y));
}

inline void addedge(int u, int v) {
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

void Prim() {
    sum = 0.0;
    memset(vis, 0, sizeof(vis));
    memset(pre, 0, sizeof(pre));
    for (int i = 1; i < n; i++) lowc[i] = d[0][i];
    vis[0] = true;
    for (int i = 1; i < n; i++) {
        double minc = inf;
        int p = -1;
        for (int j = 0; j < n; j++) {
            if (!vis[j] && minc > lowc[j]) {
                minc = lowc[j];
                p = j;
            }
        }
        sum += minc;
        vis[p] = true;
        addedge(p, pre[p]);
        addedge(pre[p], p);
        for (int j = 0; j < n; j++) {
            if (!vis[j] && lowc[j] > d[p][j]) {
                lowc[j] = d[p][j];
                pre[j] = p;
            }
        }
    }
}

double dfs(int u, int fa, int root) {
    double ans = fa == root ? inf : d[root][u];
    for (int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to;
        if (v == fa) continue;
        double temp = dfs(v, u, root);
        ans = min(ans, temp);
        dp[u][v] = dp[v][u] = min(dp[u][v], temp);
    }
    return ans;
}

void dfs1(int u, int fa) {
    for (int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to;
        if (v == fa) continue;
        if (fa) ans = max(ans, sum - d[u][v] + dp[u][v]);
        dfs1(v, u);
    }
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i++) scanf("%lf%lf", &a[i].x, &a[i].y);
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                d[i][j] = d[j][i] = distan(a[i], a[j]);
            }
        }
        cnt = 0;
        memset(head, -1, sizeof(head));
        Prim();
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < n; ++j) dp[i][j] = inf;
        for (int i = 0; i < n; i++) dfs(i, -1, i);
        ans = sum;
        dfs1(0, 0);
        ans *= 1.0 * m;
        printf("%.2f\n", ans);
    }
    return 0;
}

最小生成树的各种题型根本没掌握...新生赛后要补补这块和并查集的坑了...

原文地址:https://www.cnblogs.com/Mrzdtz220/p/10514472.html

时间: 2024-10-16 11:56:08

Install Air Conditioning HDU - 4756(最小生成树+树形dp)的相关文章

hdu 4126 Genghis Khan the Conqueror hdu 4756 Install Air Conditioning 最小生成树

这两题思路一样.先说下题意. 第一道就是一张图,q个操作,每次将一个边x,y增大到z,求出此时的最小生成树的值w,输出这q个w的平均值. 第二道是一张完全图,但是有一条未知边不能选,求最小生成树最大可能是多少. 对于第一道题,先求出最小生成树,对于每个操作x,y,z,假设x,y不是树边,那么w不变,如果是树边,那么假设这条边连接了u,v两个点集,那么只要添上一条两个点集间所有边的最小的那条即可.但是复杂度为n3,所以为了降低复杂度,要预处理出这条最小边,用dp[ i ][ j ]表示i,j两集合

HDU 4756 Install Air Conditioning

Install Air Conditioning Time Limit: 2000ms Memory Limit: 65535KB This problem will be judged on HDU. Original ID: 475664-bit integer IO format: %I64d      Java class name: Main   NJUST carries on the tradition of HaJunGong. NJUST, who keeps up the ”

HDU 4756 Install Air Conditioning(次小生成树)

题目大意:给你n个点然后让你求出去掉一条边之后所形成的最小生成树. 比较基础的次小生成树吧...先prime一遍求出最小生成树,在dfs求出次小生成树. Install Air Conditioning Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 1038    Accepted Submission(s): 240 Problem

hdu 1011(树形dp)

Mark.看着吴神博客写的,还未完全懂. 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <queue> 7 #include <set> 8 #include <map> 9 #include <string>

HDU 2196Computer(树形DP)

给你一颗边带权值的树,求树上的每一点距离其最远的一个点的距离 比较典型的题了,主要方法是进行两次DFS,第一次DFS求出每一个点距离它的子树的最远距离和次远距离,然后第二次DFS从父节点传过来另一侧的树上的距离它的最远距离进行一次比较便可得出任意点的最远距离了 之所以需要记录最远和次远是为了辨别父节点的最远距离是否是根据自己得来,如果是的话应该选择父节点的次远距离,保证结果的准确性 1 //#pragma comment(linker,"/STACK:102400000,102400000&qu

【树形DP】 HDU 4756 Install Air Conditioning

通道 题意:给n个点,现在要使这n个点连通,并且要求代价最小.现在有2个点之间不能直接连通(除了第一个点),求最小代价 思路:先求mst,然后枚举边,对于生成树上的边替换,用树形dp O(N^2)求出每条生成树边的最小替代边.然后替换后的最大值 代码: #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <algorithm> using

HDU 2196 Computer 树形DP经典题

链接:http://acm.hdu.edu.cn/showproblem.php? pid=2196 题意:每一个电脑都用线连接到了还有一台电脑,连接用的线有一定的长度,最后把全部电脑连成了一棵树,问每台电脑和其它电脑的最远距离是多少. 思路:这是一道树形DP的经典题目.须要两次DFS,第一次DFS找到树上全部的节点在不同子树中的最远距离和次远的距离(在递归中进行动态规划就可以),第二次DFS从根向下更新出终于答案.对于每次更新到的节点u,他的最远距离可能是来自u的子树,或者是u的父亲节点的最远

HDU 4714 Tree2cycle (树形DP)

题意:给定一棵树,断开一条边或者接上一条边都要花费 1,问你花费最少把这棵树就成一个环. 析:树形DP,想一想,要想把一棵树变成一个环,那么就要把一些枝枝叶叶都换掉,对于一个分叉是大于等于2的我们一定要把它从父结点上剪下来是最优的, 因为如果这样剪下来再粘上花费是2(先不管另一端),如果分别剪下来再拼起来,肯定是多花了,因为多了拼起来这一步,知道这,就好做了.先到叶子结点, 然后再回来计算到底要花多少. 代码如下: #pragma comment(linker, "/STACK:10240000

HDU 3899 简单树形DP

题意:一棵树,给出每个点的权值和每条边的长度, 点j到点i的代价为点j的权值乘以连接i和j的边的长度.求点x使得所有点到点x的代价最小,输出 虽然还是不太懂树形DP是什么意思,先把代码贴出来把. 这道题目的做法是:先进行一次DFS,以每个节点为根,求出它下面节点到它的数量和. 再进行一次DFS,以每个节点为根,求出它下面节点到它的花费总和. source code: #pragma comment(linker, "/STACK:16777216") //for c++ Compile