题意:
题意:有n个池塘和m个管道;每个池塘的价值是v, 现在要删除池塘,删除的池塘必须是最多只连接一个管道,否则会爆炸;求最后相连的池塘是奇数个的价值总和是多少。
思路:
拓扑排序后求和
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4+ 7;
typedef long long ll;
const int inf = 0x3f3f3f3f;
int n,m,t,p;
ll a[maxn];
int father[maxn];
ll sum[maxn];
int cnt[maxn];
int degree[maxn];
int vis[maxn];
int x,y;
vector<int>vec[maxn];
int find_(int x)
{
return x == father[x] ? x : father[x] = find_(father[x]);
}
void join(int i,int j)
{
int u = find_(i);
int v = find_(j);
if(u !=v )
{
father[max(u,v)] = min(u,v);
sum[min(u,v)] += sum[max(u,v)];
cnt[min(u,v)] += cnt[max(u,v)];
}
}
void init()
{
memset(degree,0,sizeof(degree));
memset(vis,0,sizeof(vis));
for(int i = 1; i<=n; i++)
{
vec[i].clear();
father[i]=i;
sum[i] = a[i];
cnt[i] = 1;
}
}
void topsort()
{
// memset(vis,0,sizeof vis);
queue <int> que;
for(int i = 1; i <= n; i++)
{
if(degree[i]<=1)
{
vis[i]=1;
que.push(i);
}
}
while(!que.empty())
{
int now = que.front();
que.pop();
for(int i = 0; i < vec[now].size(); i++)
{
int u = vec[now][i];
degree[u]--;
if(!vis[u] && degree[u] <= 1 )
{
que.push(u);
vis[u] = 1;
}
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i = 1; i<=n; i++)
cin>>a[i];
init();
for(int i = 1; i <= m; i++)
{
cin>>x>>y;
vec[x].push_back(y);
vec[y].push_back(x);
degree[x]++;
degree[y]++;
}
topsort();
for(int i = 1; i <= n; i++)
{
if(!vis[i])
{
for(int j = 0; j < vec[i].size(); j++)
{
int u = vec[i][j];
if(!vis[u])
join(i,u);
}
}
}
ll ans = 0;
for(int i = 1; i <= n; i ++)
{
if((find_(i) == i) && (cnt[i]&1) && (!vis[i]) )
ans += sum[i];
}
cout<<ans<<endl;
}
}