LightOJ 1380 – Teleport 【最小树形图】

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1380

最小树形图也就是有向图的最小生成树。普通的prim无法求解。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <queue>

using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 1010;
const int MAXM = 400100;

struct Edge
{
    int u, v, cost;
};
Edge edge[MAXM];
int pre[MAXN], id[MAXN], visit[MAXN], in[MAXN];
int zhuliu(int root, int n, int m, Edge edge[])
{
    int res = 0, u, v;
    while (1)
    {
        for (int i = 0; i < n; i++)
            in[i] = INF;
        for (int i = 0; i < m; i++)
            if (edge[i].u != edge[i].v && edge[i].cost < in[edge[i].v])
            {
                pre[edge[i].v] = edge[i].u;
                in[edge[i].v] = edge[i].cost;
            }
        for (int i = 0; i < n; i++)
            if (i != root && in[i] == INF)
                return -1;
        int tn = 0;
        memset(id, -1, sizeof(id));
        memset(visit, -1, sizeof(visit));
        in[root] = 0;
        for (int i = 0; i < n; i++)
        {
            res += in[i];
            v = i;
            while (visit[v] != i && id[v] == -1 && v != root)
            {
                visit[v] = i;
                v = pre[v];
            }
            if (v != root && id[v] == -1)
            {
                for (int u = pre[v]; u != v; u = pre[u])
                    id[u] = tn;
                id[v] = tn++;
            }
        }
        if (tn == 0)break;
        for (int i = 0; i < n; i++)
            if (id[i] == -1)
                id[i] = tn++;
        for (int i = 0; i < m;)
        {
            v = edge[i].v;
            edge[i].u = id[edge[i].u];
            edge[i].v = id[edge[i].v];
            if (edge[i].u != edge[i].v)
                edge[i++].cost -= in[v];
            else
                swap(edge[i], edge[--m]);
        }
        n = tn;
        root = id[root];
    }
    return res;
}
int g[MAXN][MAXN];

int a[100];
int sum[100];

void init(int n)
{
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n; j++)
        {
            if (i == j)
                g[i][j] = 0;
            else
                g[i][j] = g[j][i] = INF;
        }
}

int main()
{
    int t, n, m, k,a,b,c;
    scanf("%lld",&t);
    for (int kk = 1; kk <= t; kk++)
    {
        scanf("%d%d%d", &n, &m, &k);
        init(n);
        while (m--)
        {
            scanf("%d%d%d", &a, &b, &c);
            if (g[a][b] > c)
                g[a][b] =  c;
        }
        int L = 0;
        for (int i = 0; i < n; i++)
            for (int j = 0; j <= n; j++)
            {
                if (g[i][j] < INF)
                {
                    edge[L].u = i;
                    edge[L].v = j;
                    edge[L++].cost = g[i][j];
                }
            }
        int ans = zhuliu(k,n,L,edge);
        if (ans != -1)
            printf("Case %d: %d\n", kk, ans);
        else
            printf("Case %d: impossible\n", kk);
    }
    return 0;
}
时间: 2024-12-22 23:22:00

LightOJ 1380 – Teleport 【最小树形图】的相关文章

bzoj4349: 最小树形图

最小树形图模板题…… 这种\(O(nm)\)的东西真的能考到么…… #include <bits/stdc++.h> #define N 60 #define INF 1000000000 using namespace std; int n, m, nn; double ai[N], an[N], ci[2][N][N], ans; int bc[N]; int ini[N], vis[N], inc[N], inl[N]; int dfn; int dfs(int t) { vis[t]

Directed_MST 最小树形图

List Directed_MST 最小树形图 List Knowledge 模板 Practice 参考资料 Knowledge 求一个图中遍历到每个点的方案中的最小边权和,显然n-1条边,即一颗树即可. 最小生成树?当然这里不是的,这里的最小树形图算法是针对有向图的. 最小树形图的第一个算法是1965年朱永津和刘振宏提出的复杂度为O(VE)的算法.简称朱刘算法. 1986年, Gabow, Galil, Spencer和Tarjan提出了一个复杂度更好的实现,其时间复杂度为O(E+VlogV

hdu2121+不定根最小树形图

算和定根最小树形图相同. 我们只需:设一个权值sumw=所有边之和+1,类似于网络流,向图中加入一个超级源点,把这个点作为虚根.虚根到其他所有点之间连上一条边,边权值为sumw. 求出的值减去sumw即为最小树形图的权值. 当然,返回-1则无解.此外,当求出的值>=2*sumw,也是无解的. 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 struct node 5 { 6 int u,v; 7

HDOJ 2121 Ice_cream’s world II 最小树形图无根树

朱刘算法 最小树形图无根树: 建立一个虚拟的根节点,向所有节点连边,权值为其他所有边的权值和+1 在求最小树形图的时候,记录和虚拟的根相连的是哪个节点 在这题中,边是从小往大加的所以直接记录的是相连的是第几号边.... Ice_cream's world II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3442    Accept

最小树形图【模板】

基于贪心和缩点的思想. 假设根的顶点是V0. (1)除了根结点外,所有的点Vi,找到以Vi为终点的最短的边,加入集合中 (pre[v]存放的是终点v的起点,In[v]存放终点为v的最短的边) (2)检查集合中有没有有向环和收缩点.若没有有向环和收缩点,结束计算:若没有有向环.但含收缩边,则跳至步骤(4):若含有有向环,则跳至步骤(3).Ps:如果出现重边,将忽略权值较高的 (3)含有有向环,则收缩有向环(缩点),把有向环收缩为一个点,其有向环内的边被收缩掉,而环外的边被保 留,构建新图,重复步骤

HDU 2121 Ice_cream’s world II (不定根最小树形图)

题目地址:HDU 2121 这题没有给定根.最容易想到的当然是暴力,枚举所有的根,但是TLE是显然的..为了处理不定根的情况,可以虚拟一个根,然后用这个根去跟所有的点连边,权值为其他所有权值的和+1,目的是防止成为最小树形图的一条边.然后跑出最小树形图后,那么这个虚拟根肯定跟一个实际根相连,这时候根就找到了,然后再在最终的总花费中减去虚拟的那条边的权值就可以了. 代码如下: #include <iostream> #include <string.h> #include <m

HDU2121 Ice_cream’s world II【最小树形图】【不定根】

Ice_cream's world II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3005    Accepted Submission(s): 704 Problem Description After awarded lands to ACMers, the queen want to choose a city be he

poj Command Network 最小树形图

规定根节点,求一颗生成树使得权值最小,但由于是有向图,所以最小生成树算法失效. 查资料后得知此类问题叫做最小树形图. 解决最小树形图问题的朱刘算法,算法核心基于找 [最小弧集->找环,消环缩点] 的思想,来慢慢构造树形图. 所有的灵魂都在这张图上.0.0 注意缩点后的弧权值的处理 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algo

AIZU AOJ 2309 Vector Compression 最小树形图(朱—刘算法)

题意简述:给定若干个相同维度的向量,寻找一种排序方法,使得所有向量的表示长度总和最低. 所谓表示长度为(Aj-r*Ai)^2,其中i<j  数据范围:向量总数和维度均小于100 思路:(1)首先Ai和Aj确定后,最小表示长度是可以在线性时间计算出来的.使用简单的二次函数分析方法即可. (2)上述可以得出任意两向量之间的距离,即为图中的边,于是问题可以转化为有向图的"最小树形图",i到j的有向边权值即为用Aj表示Ai的最小表示长度. (3)朱-刘算法简述: 首先对除根以外的点选择一