气的不行之STL应用-B - Ponds-拓扑排序+搜索

给定一个图,让你把连通度小于2的点都给删掉。然后把联通块点数为奇数的联通块对应的权重加起来,问你结果是多少。。
一开始以为是 割点,没错,是割点。。。。。后来打对了模板了发现不是割点qwq。。
然后又感觉一次判断连通度就可以了。。
wawawawawa
中间有一点微微的感觉是拓扑排序的赶脚,又想用反向边那一套来整,后来直接放弃了。。。
知道了拓扑后,第二天用拓扑排序。又是wa
众所周知拓扑不能搞得环,如果是有向图就是回路。
所以他会留下回路,那么问题来了,在拓扑后,所有的度都会是0么。。
答案是不是。。
我竟然以为是,。。。。
对于最外面的点,是-1,中间的是0,和环连接的那个点1.
所以在判断的时候,只要参加过拓扑排序的多应该vis掉。然后再整。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
const int maxn=1e5+5;
using namespace std;
int sum;
long long all;
vector<int>G[maxn];
bool vis[maxn];
long long v[maxn];
int indgree[maxn];
int dfs(int a)
{   for(int i=0;i<G[a].size();i++)
      {   if(!vis[G[a][i]])
          {   sum++;
             all+=v[G[a][i]];
             vis[G[a][i]]=true;
              dfs(G[a][i]);
          }
      }

return 0;
}
int main()
{  int m,n;
   int a,b;
   int t;
     cin>>t;
    while(t--)
{   scanf("%d%d",&m,&n);
       for(int i=0;i<maxn;i++)
          G[i].clear();
       memset(indgree,0,sizeof(indgree));
       memset(v,0,sizeof(v));
      memset(vis,false,sizeof(vis));
       for(int i=1;i<=m;i++)
         scanf("%lld",&v[i]);
       for(int i=1;i<=n;i++)
       {  scanf("%d%d",&a,&b);
          G[a].push_back(b);
          G[b].push_back(a);
          indgree[a]++;
          indgree[b]++;
       }
       queue<int>q;
       for(int i=1;i<=m;i++)
       {  if(indgree[i]==1)
           {  vis[i]=true;
               q.push(i);}
       }
       while(!q.empty())
       {   int u=q.front();
            q.pop();
           for(int i=0;i<G[u].size();i++)
           {   int s=G[u][i];
               indgree[s]--;
               indgree[u]--;
               if(indgree[s]==1)
               { vis[s]=true;
                   q.push(s);
               }
           }
       }
      /*最开始的时候是拓扑完判断度是否为0.。。当然错了。
      度可以是 -1,0,1;
      */
       long long ans=0;
       for(int i=1;i<=m;i++)
       {   if(!vis[i])
          {   sum=1;
          vis[i]=true;
             all=v[i];
             //cout<<i<<endl;
              dfs(i);
              if(sum%2==1&&sum>1)
              {  ans+=all;
              }
          }
}
   cout<<ans<<endl;
   }
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值