拓扑排序(栈模拟)+dfs(hdu 5438)

题目:http://acm.split.hdu.edu.cn/showproblem.php?pid=5438

题意:有一些带权的池塘,池塘间用管道连接,要求去掉剩下池塘中度数<=1的池塘,求剩下的池塘中卫奇数图的权值和

题解:先利用拓扑方法,利用栈,将所有度数<=1的点进栈,每次对出栈的池塘遍历连接的池塘度数-1,将新产生的度数<=1的进栈,直至去完所有满足的池塘,用vis数组记录去掉的点,然后同过dfs遍历,每次遍历时记录遍历的池塘数和权值,若满足为奇数就进行加,在遍历时要通过标记vis数组来记录该值已经被遍历,防止重复计数,最后得出答案

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>

using namespace std;
int value[10050];//记录权值
typedef struct
{
    int e,next;
}Edge;
Edge edge[200500];//记录边
int head[10050];//记录以该点位头的边
int du[10050];//记录度数
bool vis[10050];//记录是否已经去掉该点和是否遍历过该点
long long sum;
void addEdge(int s,int e,int i)//加边
{
    edge[i].e=e;
    edge[i].next=head[s];
    head[s]=i;
}
void dfs(int root,int& num)
{
    sum+=value[root];
    vis[root]=1;
    int nextroot=head[root];
    while(nextroot!=-1)
    {
        if(vis[edge[nextroot].e]) {nextroot=edge[nextroot].next;continue;}
        num++;
        dfs(edge[nextroot].e,num);
        nextroot=edge[nextroot].next;
    }
}
int main()
{
    int t,n,e;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&e);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&value[i]);
        }
        memset(du,0,sizeof(du));
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<e;i++)
        {
            int s,e;
            scanf("%d %d",&s,&e);
            addEdge(s,e,2*i);
            addEdge(e,s,2*i+1);
            du[s]++;
            du[e]++;
        }
        queue<int> que;
        for(int i=1;i<=n;i++)
        {
            if(du[i]<=1){que.push(i);vis[i]=1;}
        }
        while(!que.empty())//拓扑排序
        {
            int now=que.front();que.pop();
            if(du[now]==1)
            {
                int next=head[now];
                while(next!=-1)
                {
                    int ed=edge[next].e;
                    du[ed]--;
                    if(du[ed]<=1 && !vis[ed]){que.push(ed);vis[ed]=1;}
                    next=edge[next].next;
                }
                head[now]=-1;
            }
        }
        long long ans=0;
        for(int i=1;i<=n;i++)//dfs
        {
            if(vis[i]) continue;
            sum=0;
            int d=1;
            dfs(i,d);
            if(d%2) ans+=sum;
        }
        printf("%lld\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值