题意:给出一张无向图,每个节点有各自的权值,问在点数为奇数的圈中的点的权值总和是多少。
通过拓扑序的做法标记出所有非圈上的点,做法就是加每条边的时候将两点的入度都加一,然后将所有度数为1的点入队,删去它的所有边,即对没条边连的点度数减一,度数减为1继续入队,直到队列为空,入过队列的点都进行标记,表示该点不在圈上,那么剩余没有标记的点一定要么在圈上、要么是单点或自环。这时候只要对于每个没有访问过的节点,DFS遍历它的连通区域,记录点数和权值和,如果点数为奇数,则统计权值和。但是注意如果只有一个点,不能算作一个圈,所以除了判断点数是否奇数,还需要判断点数大于1。
1 #include<stdio.h>
2 #include<string.h>
3 #include<algorithm>
4 #include<math.h>
5 #include<queue>
6 #include<iostream>
7 typedef long long ll;
8 using namespace std;
9
10 const int maxn=100050;
11 const int maxm=200050;
12
13 int head[maxn],point[maxm],nxt[maxm],id[maxn],size,vis[maxn];
14 int v[maxn];
15 int n,m;
16
17 void init(){
18 memset(head,-1,sizeof(head));
19 size=0;
20 memset(id,0,sizeof(id));
21 memset(vis,0,sizeof(vis));
22 }
23
24 void add(int a,int b){
25 point[size]=b;
26 nxt[size]=head[a];
27 head[a]=size++;
28 id[b]++;
29 point[size]=a;
30 nxt[size]=head[b];
31 head[b]=size++;
32 id[a]++;
33 }
34
35 void topo(){
36 queue<int>q;
37 for(int i=1;i<=n;++i)if(id[i]==1){
38 id[i]=-1;
39 q.push(i);
40 }
41 while(!q.empty()){
42 int u=q.front();
43 q.pop();
44 for(int i=head[u];~i;i=nxt[i]){
45 int j=point[i];
46 id[j]--;
47 if(id[j]==1){
48 id[j]=-1;
49 q.push(j);
50 }
51 }
52 }
53 }
54
55 int nnum=0;
56 ll sum=0;
57
58 void dfs(int s){
59 vis[s]=1;
60 nnum++;
61 sum+=v[s];
62 for(int i=head[s];~i;i=nxt[i]){
63 int j=point[i];
64 if(!vis[j]&&id[j]>0)dfs(j);
65 }
66 }
67
68 int main(){
69 int T;
70 scanf("%d",&T);
71 while(T--){
72 scanf("%d%d",&n,&m);
73 init();
74 for(int i=1;i<=n;++i)scanf("%d",&v[i]);
75 while(m--){
76 int a,b;
77 scanf("%d%d",&a,&b);
78 add(a,b);
79 }
80 topo();
81 ll ans=0;
82 for(int i=1;i<=n;++i){
83 if(!vis[i]&&id[i]>0){
84 sum=0;
85 nnum=0;
86 dfs(i);
87 if(nnum%2&&nnum>1)ans+=sum;
88 }
89 }
90 cout<<ans<<endl;
91 }
92 return 0;
93 }