zzuoj 10409

此题是省赛 D题 点击打开链接


 比赛时没有仔细看这道题 乍一看 什么流 什么最小费用 又因为比赛前正在写网络流 当下立即以为是最小费用最大流 想套模版 发现又不是费用流 一时有没有什么好想法 后来就一直卡c了 也没有时间去看这道题目


 然后听人说这道题仍旧可以用最短路去做 又仔细老板探讨了一下 感觉他所说的dijkstra 完全就是prim  只不过要自己选定费用最小的源点罢了


还有理工大大牛套最小树形图的模版过的 汗颜 根本不知道什么是最小树形图


我个人理解还是最小生成树  设置一个虚拟汇点 和每个区域连边 权值为建水库的费用 这样就把每个带费用限制的节点拆成了边 然后就是直接裸最小生成树 kruskal prim都可以

这里给出一个kruskal写的


#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
 
const int N = 310;
 
#define INF 0xfffffff
 
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
 
#define maxn 310
#define INF 0xfffffff
 
int father[maxn], n;
int Find (int x);
int Union (int x, int y);
double kruskal ();
 
struct node
{
    int x, y, len;
    friend  bool operator < (node a, node b)
    {
        return a.len > b.len;
    }
};
 
priority_queue <node> que;
 
int main ()
{
    int t;
    cin >> t;
    while (t--)
    {
        cin >> n;
        int x;
        node q;
        for (int i=1; i<=n; i++)
        {
            q.x = 0, q.y = i;
            cin >> q.len;
            que.push (q);
        }
        for (int i=1; i<=n; i++)
            for (int j=1; j<=n; j++)
            {
                cin >> q.len;
                q.x = i, q.y = j;
                que.push (q);
            }
 
        cout << kruskal() << endl;
    }
    return 0;
}
 
int Find (int x)
{
    return father[x] == x ? father[x] : Find (father[x]);
}
 
int Union (int x, int y)
{
    int a = Find (x), b = Find (y);
 
    if (a != b)
    {
        father[a] = b;
        return 1;
    }
    return 0;
}
 
double kruskal ()
{
    node s;
    int i;
    double sum = 0;
 
    for (i=0; i<=n; i++)
        father[i] = i;
 
    while (que.size())
    {
        s = que.top (), que.pop ();
        if (Union (s.x, s.y))
            sum += s.len;
    }
 
    return sum;
}


然后是直接用prim不拆点的做法 dis数组里面初始化为每个区域建立水库的费用 然后直接prim

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
#include <iterator>
#include <cmath>
#include <deque>
#include <stack>
#include <cctype>
#include <iomanip>
using namespace std;

typedef long long ll;
typedef long double ld;

const int N = 310;
const int INF = 0xfffffff;
const double EPS = 1e-8;
const ll MOD = 1e9 + 7;
const ld PI = acos (-1.0);

#define INFL 0x7fffffffffffffffLL
#define met(a, b) memset(a, b, sizeof(a))
#define put(a) cout << setiosflags(ios::fixed) << setprecision(a)

int g[N][N], vis[N], dis[N], cost[N];
void prim (int n);

int main ()
{
    int t, n;
    cin >> t;
    while (t--)
    {
        cin >> n;
        for (int i=1; i<=n; i++)
            cin >> dis[i];

        for (int i=1; i<=n; i++)
            for (int j=1; j<=n; j++)
            cin >> g[i][j];

        prim (n);
    }
    return 0;
}

void prim (int n)
{
    met (vis, 0);
    for (int i=1; i<n; i++)
    {
        int minx = INF, u = 1;
        for (int j=1; j<=n; j++)
        {
            if (!vis[j] && minx > dis[j])
                minx = dis[j], u = j;
        }
        vis[u] = 1;

        for (int j=1; j<=n; j++)
        {
            if (!vis[j] && dis[j] > g[u][j])
                dis[j] = g[u][j];
        }
    }
    int sum = 0;
    for (int i=1; i<=n; i++)
        sum += dis[i];

    cout << sum << endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值