题目地址:点击打开链接
题意: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;
}
大神地址: 点击打开链接