1 7 7 1 2 3 4 5 6 7 1 4 1 5 4 5 2 3 2 6 3 6 2 7
21
题意:给你p个池塘以及每个池塘的价值,再给你m条边(即池塘ai与池塘bi之间连接的管道暂且称为边),问在移除度小于2(即最终留下的池塘的度均要大于等于2)的池塘之后,所有回路中有奇数个池塘的回路的价值之和是多少
这题描述起来可能会有些拗口,所以,我们暂且拿样例来说明一下
按照样例将图画出来,就是上图这个样子,可以移除的池塘只有7,而剩下的则是1~6这6个池塘,它们组成两个回路,每个回路的池塘数为3,是奇数,故符合要求,所以总和为1+2+3+4+5+6=21
解题思路:其实我们按照题目说的来就可以了,先将度小于2的池塘移除,这一步利用dfs可以做到,遍历p个点,将一开始度就小于2的池塘移除,这样就会导致与该池塘相邻的池塘度都减少1,所以要用到dfs删点
而删完点之后,则仍旧遍历未删除的点,再一次dfs记录各自回路中点的个数及池塘价值之和,以确定是否要加入最终结果中
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> #include<math.h> #include<vector> #include<map> #include<set> #include<stdlib.h> #include<cmath> #include<string> #include<algorithm> #include<iostream> #define exp 1e-10 using namespace std; const int N = 10005; const int inf = 1000000000; const int mod = 2009; struct node { int to,next; }e[20*N]; int s[N],w[N],h[N],k,cnt; __int64 sum,ans; bool v[N]; void add_edge(int u,int v) { e[k].to=v; e[k].next=h[u]; h[u]=k++; } void del(int u) { for(int i=h[u];i+1;i=e[i].next) if(!v[e[i].to]) { if(w[e[i].to]==2) { w[e[i].to]=0; v[e[i].to]=true; del(e[i].to); return ; } else if(w[e[i].to]==1) { v[e[i].to]=true; w[e[i].to]=0; return ; } else w[e[i].to]--; } } void dfs(int u) { sum+=s[u]; cnt++;v[u]=true; for(int i=h[u];i+1;i=e[i].next) if(!v[e[i].to]) dfs(e[i].to); } int main() { int t,p,m,i,a,b; scanf("%d",&t); while(t--) { memset(w,0,sizeof(w)); memset(h,-1,sizeof(h)); memset(v,false,sizeof(v)); ans=0; scanf("%d%d",&p,&m); for(i=1;i<=p;i++) scanf("%d",&s[i]); for(i=k=0;i<m;i++) { scanf("%d%d",&a,&b); add_edge(a,b); add_edge(b,a); w[a]++;w[b]++; } for(i=1;i<=p;i++) if(w[i]<2) { v[i]=true; if(w[i]==1) del(i); } for(i=1;i<=p;i++) if(!v[i]) { cnt=0;sum=0; dfs(i);//printf("%d###%d\n",i,cnt); if(cnt&1) ans+=sum; } printf("%I64d\n",ans); } return 0; }菜鸟成长记