avatar
fireworks99
keep hungry keep foolish

POJ 1251 Jungle roads

Description

左侧图显示当前所有使用中的道路,以及现在每月的维护费用。当然,村庄之间必需有一些公路能够相通,即使路线并不像以前一样短。怎样才使每月的花费最小,并且所维持的道路,将连接所有村庄。

Link http://poj.org/problem?id=1251

Kruskal

并查集 + sort(edge, edge + cnt, cmp) = Kruskal

结构体存边:遍历每条边,unite每条边的两点

Code of Kruskal

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 30;

int n;///n个点
int ans;
int pre[N];

int cnt;
struct edge
{
    int there, here, w;
} a[1005];

bool cmp(edge a, edge b)
{
    return a.w < b.w;
}

void init()
{
    cnt = 0;
    ans = 0;
    for(int i = 0; i <= n; ++i)
        pre[i] = i;
}

int found(int x)
{
    if(x != pre[x])
        pre[x] = found(pre[x]);
    return pre[x];
}

int unite(edge t)
{
    int x = found(t.there);
    int y = found(t.here);
    if(x != y)
    {
        pre[y] = x;
        return t.w;
    }
    return 0;
}

int main()
{
///    cout << int('A') << '\n';    65
///    cout << 'A' - 64 << '\n';    1
    while(~scanf("%d", &n) && n)
    {
//        getchar();
        init();
        for(int i = 1; i < n; ++i)
        {
            char now, nxt;
            int num, w;
//            scanf("%c%d", &now, &num);
//            getchar();
            cin >> now >> num;
            while(num--)
            {
//                scanf("%c%d", &nxt, &w);
//                getchar();
                cin >> nxt >> w;
                a[cnt].there = now - 65;
                a[cnt].here = nxt - 65;
                a[cnt++].w = w;
            }
        }
        sort(a, a + cnt, cmp);
        for(int i = 0; i < cnt; ++i)///遍历所有边
            ans += unite(a[i]);
        cout << ans << '\n';
    }
    return 0;
}

对于这个题,用scanf输入总会RE,非法内存访问?cin一次过

Prim

查找部分类似Dijkstra

邻接矩阵存边:遍历每个点,依次连接

注意图是双向的!

邻接矩阵存边: 注定遍历“点”(某些算法所必需)

结构体存边: 注定遍历“边”(高效)

Code of Prim

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;

int n;///点的个数
bool vis[30];
int mp[30][30], low[30];///low[i]表示已成图所有点到点i的最小权值

void prim()
{
    int ans = 0;
    memset(vis, 0, sizeof(vis));

    int pos = 1;///起点
    vis[1] = 1;
    for(int i = 1; i <= n; ++i)///更新当前检测点到其他所有点的最小距离
        low[i] = mp[pos][i];

    int cnt = n;
    while(--cnt)///n个点,循环n-1次,一次不能多
    {
        int mmin = INF;
        for(int i = 1; i <= n; ++i)///类dijkstra查找
            if(vis[i] == 0 && low[i] < mmin)///未连接入图且...
            {
                mmin = low[i];
                pos = i;
            }

///     if(mmin == INF)有些题不能连成树

        vis[pos] = 1;///连入图并更新已成图所有点到其他所有点的最小距离
        ans += mmin;
        for(int i = 1; i <= n; ++i)
        {
            if(vis[i] == 0 && low[i] > mp[pos][i])
                low[i] = mp[pos][i];
        }
    }
    cout << ans << '\n';
}

int main()
{
    while(~scanf("%d", &n) && n)
    {
        memset(mp, INF, sizeof(mp));
        for(int i = 1; i < n; ++i)
        {
            char now, nxt;
            int num, w;
            cin >> now >> num;
            while(num--)
            {
                cin >> nxt >> w;
                mp[now - 64][nxt - 64] = w;///点为1~n
                mp[nxt - 64][now - 64] = w;///点为1~n
            }
        }
        prim();
    }
    return 0;
}
Site by Baole Zhao | Powered by Hexo | theme PreciousJoy