kuangbin专题六最小生成树总结

这个专题主要就是学会prim和kruskal算法,另外图论最重要的就是要会建图。
J - Borg Maze
这题一开始没看懂题意,看懂之后就知道是最小生成树了,所以先bfs算出每个A和S到其他点的距离,然后求最小生成树就行了,不过最后wa了好多发。。

while (!Q.empty())
    {
        node u = Q.front();Q.pop();
        for (int i = 0;i < num;i++)if(i!=theid)
        {
            if (u.x == nodes[i].x&&u.y == nodes[i].y)
            {
                addedge(theid, i, u.d);
                nownum++;
                break;
            }
        }
        if (nownum == num)break;
        if (vis[u.x][u.y])continue;
        vis[u.x][u.y] = 1;
        for (int i = 0;i < 4;i++)
        {
            int tmpx = u.x + dir[i][0];
            int tmpy = u.y + dir[i][1];
            if (tmpx < 0 || tmpx >= X || tmpy < 0 || tmpy >= Y)continue;
            if (Map[tmpx][tmpy] == '#')continue;
            if (vis[tmpx][tmpy] == 0)
            {
                Q.push(node(tmpx, tmpy, u.d + 1));
            }
        }
    }

这是bfs部分,大家可以看到我加了一个剪枝,当nownum==num时就直接break,num是A和S的总个数,nownum是已经找到的个数。然而就是因为这个wa到怀疑人生。。原因是我加错地方了,因为他每个点是先判断是不是S或A,再看vis[u.x][u.y]是不是等于1,所以即是到了之前到过的点,它的nownum也会加。所以只要把这句话提到前面就行了。
当然不加也可以。

#include<iostream>
#include<string>
#include<map>
#include<queue>
#include<cstring>
#include<stdio.h>
#include<stdlib.h>
#include<vector>
using namespace std;
const int maxn = 500;

inline char read()
{
    char c = getchar();
    while (c == '\n')c = getchar();
    return c;
    /*while (c < '0' || c > '9') { if (c == '-')f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x*f;*/
}

struct Edge
{
    int from, to, dist;
    Edge(int _f,int _t,int _d):from(_f),to(_t),dist(_d){}
    Edge(){}
    bool operator<(const Edge &e)const
    {
        return dist > e.dist;
    }
};
vector<Edge>G[maxn];
char Map[maxn][maxn];
void addedge(int u, int v, int dis)
{
    G[u].push_back(Edge(u, v, dis));
}

struct node
{
    int x, y, d;
    node(int _x,int _y,int _d):x(_x),y(_y),d(_d){}
    node(){}
}nodes[maxn];

int num;

bool vis[maxn][maxn];
int dir[4][2] = { -1,0,1,0,0,-1,0,1 };
int X, Y;
void bfs(int x, int y,int theidx)
{
    memset(vis, 0, sizeof(vis));
    int theid = theidx;
    queue<node>Q;
    Q.push(node(x,y,0));
    int nownum = 0;
    while (!Q.empty())
    {
        node u = Q.front();Q.pop();
        for (int i = 0;i < num;i++)if(i!=theid)
        {
            if (u.x == nodes[i].x&&u.y == nodes[i].y)
            {
                addedge(theid, i, u.d);
                nownum++;
                break;
            }
        }
        //if (nownum == num)break;
        if (vis[u.x][u.y])continue;
        vis[u.x][u.y] = 1;
        for (int i = 0;i < 4;i++)
        {
            int tmpx = u.x + dir[i][0];
            int tmpy = u.y + dir[i][1];
            if (tmpx < 0 || tmpx >= X || tmpy < 0 || tmpy >= Y)continue;
            if (Map[tmpx][tmpy] == '#')continue;
            if (vis[tmpx][tmpy] == 0)
            {
                Q.push(node(tmpx, tmpy, u.d + 1));
            }
        }
    }
}

bool vis1[maxn];
int prim()
{
    memset(vis1, 0, sizeof(vis1));
    priority_queue<Edge>Q;
    vis1[0] = 1;
    for (int i = 0;i < G[0].size();i++)
        Q.push(G[0][i]);
    int edgenum = num - 1;
    int ans = 0;
    while (!Q.empty()&&edgenum)
    {
        Edge e = Q.top();Q.pop();
        if (vis1[e.to])continue;
        ans += e.dist;
        edgenum--;
        vis1[e.to] = 1;
        for (int i = 0;i < G[e.to].size();i++)
        {
            Edge tmp = G[e.to][i];
            if (!vis1[tmp.to])
                Q.push(tmp);
        }
    }
    return ans;
}



int main()
{
    int T;
    char b[100];
    gets(b);
    sscanf(b,"%d", &T);

    while (T--)
    {
        num = 1;
        for (int i = 0;i < maxn;i++)G[i].clear();
        gets(b);
        sscanf(b,"%d %d", &Y, &X);
        //read();
        for (int i = 0;i < X;i++)
        {
            gets(Map[i]);
            for (int j = 0;j < Y;j++)
                if (Map[i][j] == 'A')
                {
                    nodes[num++] = node(i, j, 0);
                }
                else if (Map[i][j] == 'S')
                    nodes[0] = node(i, j, 0);
        }
        for (int i = 0;i <num;i++)
        {
            bfs(nodes[i].x,nodes[i].y,i);
        }
        int ans = prim();
        printf("%d\n", ans);
    }
    return 0;
}

K - The Unique MST
判断次小生成树和最小生成树是否一样,博主不会写次小生成树。。所以我们可以先求最小生成树,然后删掉最小生成树的某些边,再跑一次kruskal看权值是不是和以前一样就行了。

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<vector>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
const int maxn = 105;
const int maxm = 10005;
struct Edge
{
    int from, to, dist;
    int flag;  // if it has been deleted
    bool flag2;// if it has equal edge
    Edge(int _f, int _t, int _d) :from(_f), to(_t), dist(_d) { flag = 0, flag2 = 0; }
    Edge(){}
}edges[maxm];
int n, m;
int f[maxn];
int find(int a) { return f[a] == a ? a : f[a] = find(f[a]); }
int e[maxm];
map<int,int>S;
bool cmp(int a, int b)
{
    return edges[a].dist < edges[b].dist;
}
vector<int>con;
int Kruskal(int times)
{

    for (int i = 1;i <= n;i++)f[i] = i;
    for (int i = 1;i <= m;i++)e[i] = i;
    sort(e+1, e + m+1, cmp);
    int u, v, rootu, rootv, dis;
    int num = 0, ans = 0;
    for (int i = 1;i <= m;i++)
    {
        int idx = e[i];
        if (edges[idx].flag)continue;
        u = edges[idx].from, v = edges[idx].to, dis = edges[idx].dist;
        rootu = find(u), rootv = find(v);
        if (rootu != rootv) { f[rootu] = rootv; ans += dis, num++;if (times == 0)con.push_back(idx); }
    }
    if (num != n - 1)return -1;
    return ans;
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        con.clear();
        S.clear();
        scanf("%d %d", &n, &m);
        int u, v, dist;
        for (int i = 1;i <= m;i++)
        {
            scanf("%d %d %d", &u, &v, &dist);
            edges[i] = Edge(u, v, dist);
            S[dist]++;
        }
        for (int i = 1;i <= m;i++)
            if (S[edges[i].dist]>1)
                edges[i].flag2 = 1;
        int before=Kruskal(0);
        int Size = con.size();
        bool flag = true;
        for (int i = 0;i < Size;i++)
        {
            int idx = con[i];
            if (edges[idx].flag2)
            {
                edges[idx].flag = 1;
                int tmp = Kruskal(1);
                if (tmp == -1)continue;
                if (tmp == before)
                {
                    flag = false;
                    break;
                }
                edges[idx].flag = 0;
            }
        }
        if (flag)cout << before << endl;
        else puts("Not Unique!");
    }
    return 0;
}

近期目标:熟悉模板,争取1A!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值