HDU 5438 Ponds(拓扑排序+并查集)

本文介绍了一种使用拓扑排序和并查集解决特定图论问题的方法,即在一个由多个顶点和边组成的无向图中,通过不断移除度数不大于1的节点及其相连边,最终求得剩余点集中点数为奇数的集合价值之和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目地址:点击打开链接

题意:p个顶点m条边构成的无向图,每次删除边数小于等于1的节点,和他相连的边消失,一直按照此规则删除点,求最后剩下的几个集合中,点数为奇数的价值和

思路:先拓扑排序不断删除点,用并查集求出集合,然后再求点数为奇数的集合的价值总和,价值总和超int了,用long long 存,还有就是用前向星存图,貌似全局数组不能用left,right 命名,好像会和系统里面的冲突,就在后面加了一个1

AC代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>

using namespace std;

const int maxn = 10010;
int pre[maxn],num[maxn],in[maxn],head[maxn];
int left1[maxn*10],right1[maxn*10];
bool vis[maxn];
long long value[maxn];
int edgenum;

struct node
{
    int v,next;
}lol[maxn*10];

int find(int x)
{
    return x == pre[x] ? x : pre[x] = find(pre[x]);
}

void merge(int x,int y)
{
    int a = find(x);
    int b = find(y);
    if(a != b)
    {
        pre[a] = b;
        num[b] += num[a];
        value[b] += value[a];
    }
}

void add(int x,int y)
{
    lol[edgenum].v = y;
    lol[edgenum].next = head[x];
    head[x] = edgenum++;
}

void Top_sort(int n)
{
    int i;
    queue<int> que;
    for(i=1; i<=n; i++)
    {
        if(in[i] <= 1)
        {
            que.push(i);
            vis[i] = false;
        }
    }
    while(!que.empty())
    {
        int m = que.front();
        que.pop();
        for(i=head[m]; i!=-1; i=lol[i].next)
        {
            int k = lol[i].v;
            if(vis[k])
            {
                in[k]--;
                if(in[k] == 1)
                {
                    que.push(k);
                    vis[k] = false;
                }
            }
        }
    }
}

int main()
{
    int t,p,m,i;
    scanf("%d",&t);
    while(t--)
    {
        memset(vis,true,sizeof(vis));
        memset(in,0,sizeof(in));
        scanf("%d%d",&p,&m);
        for(i=1; i<=p; i++)
        {
            scanf("%I64d",&value[i]);
            pre[i] = i;
            head[i] = -1;
            num[i] = 1;
        }
        edgenum = 0;
        for(i=1; i<=m; i++)
        {
            scanf("%d%d",&left1[i],&right1[i]);
            add(left1[i],right1[i]);
            add(right1[i],left1[i]);
            in[left1[i]]++;
            in[right1[i]]++;
        }
        Top_sort(p);
        for(i=1; i<=m; i++)
        {
            if(vis[left1[i]] && vis[right1[i]])
            {
                merge(left1[i],right1[i]);
            }
        }
        long long ans = 0;
        for(i=1; i<=p; i++)
        {
            if(i == pre[i] && vis[i] && (num[i]&1))
                ans += value[i];
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

大神地址: 点击打开链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值