HDU 5438 Ponds (2015年长春赛区网络赛B题)

1.题目描述:点击打开链接

2.解题思路:本题利用拓扑排序+并查集解决。由于以前没用过用队列来模拟一个拓扑排序过程,比赛时候这道题做的异常艰难才通过==。如果用队列来处理的话,就会方便很多,首先入队列的是degree小于2的点,然后从这些点出发,和他相邻的点的degree都要减小1,如果发现相邻结点的degree也小于2了,那么加入队列,同时标记所有degre小于2的点,表示他们已经被删除了。这样,剩下的没有被标记的点一定是构成了一个环,然后用并查集来更新连通块的个数,权值,最后求和即可。

3.代码:

#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<complex>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define me(s)  memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;

const int N=10000+5;
struct Edge
{
    int u,v;
}e[100000+10];
vector<int>g[N];
int p[N],c[N];
ll w[N];
int deg[N],vis[N];
int n,m;

void init()
{
    me(g);me(vis);me(deg);
    for(int i=0;i<n;i++)
        p[i]=i,c[i]=1;
}
int find(int x){return p[x]==x?x:p[x]=find(p[x]);}
void addedge(int id,int u,int v)
{
    g[u].push_back(v);
    g[v].push_back(u);
    deg[u]++,deg[v]++;
    e[id].u=u,e[id].v=v;
}

void toposort()//利用一个队列来模拟一个拓扑排序
{
    queue<int>q;
    me(vis);
    for(int i=0;i<n;i++)
        if(deg[i]<2)
        {
            q.push(i);
            vis[i]=1;
        }
    while(!q.empty())
    {
        int u=q.front();q.pop();
        int len=g[u].size();
        for(int i=0;i<len;i++)
        {
            int v=g[u][i];
            if(vis[v])continue;
            deg[v]--;
            if(deg[v]<2)
            {
                vis[v]=1;
                q.push(v);
            }
        }
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i=0;i<n;i++)
            scanf("%I64d",&w[i]);
        int u,v;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            u--,v--;
            addedge(i,u,v);
        }
        toposort();
        for(int i=0;i<m;i++)
        {
            int u=e[i].u,v=e[i].v;
            if(vis[u]||vis[v])continue;
            int x=find(u),y=find(v);
            if(x!=y)
            {
                c[y]+=c[x];
                w[y]+=w[x];
                p[x]=y;
            }
        }
        ll ans=0;
        for(int i=0;i<n;i++)
            if(!vis[i]&&p[i]==i&&(c[i]&1))
                    ans+=w[i];
        printf("%I64d\n",ans);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值