题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5438
题面:
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
题目大意:
给定一些池塘,池塘之间连有一些管道。要求将不连管道或者只连一根管道的池塘消去,问最后剩下连在一起且池塘个数为奇数的池塘权值总和。
解题:
比赛的时候,以为是什么奇环,后来发现又不是,思路整体跑偏了。正确的解法是,通过bfs或者dfs不断消去度数为1的点,消完之后,再用dfs找联通块即可。以下提供两种解法,实际上没什么实质差别,复杂度都为O(m),因为每条边最多遍历一次。
解法一:
dfs+dfs
代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> #include <queue> using namespace std; #define LL long long int pond[10010]; //邻接表 struct edge { int next,to,vis;//下一条边序号,到哪个点,边是否被断开 }store[200010]; int head[10010],cnt,degree[10010],num;//head存储每个点连向的第一条边的存储下标,-1代表该点当前已经没有边了 //cnt加边的下标,degree度数,num联通块中的块数 bool vist[10010];//数联通块时的标记 LL sum;//存储联通块的总和 //加边 void addedge(int a,int b) { store[cnt].to=b; store[cnt].next=head[a]; store[cnt].vis=false; head[a]=cnt++; } //消去池塘 void dfs(int x) { int tmp; tmp=head[x]; degree[x]=0; //还未到最后一条边 while(tmp!=-1) { if(degree[store[tmp].to]) { //tmp和tmp^1代表相邻两条边 store[tmp].vis=store[tmp^1].vis=true; degree[store[tmp].to]--; //如果度数为1,继续搜索 if(degree[store[tmp].to]==1) dfs(store[tmp].to); } //移向下一条边 tmp=store[tmp].next; } return; } void dfs2(int x) { int tmp,v; vist[x]=1; tmp=head[x]; while(tmp!=-1) { //如果这条边还没断开 if(!store[tmp].vis) { v=store[tmp].to; if(!vist[v]&°ree[v]) { num++; sum+=pond[v]; dfs2(v); } } tmp=store[tmp].next; } } int main() { int t,p,m,u,v,tmp,cas=1; LL ans; scanf("%d",&t); while(t--) { scanf("%d%d",&p,&m); memset(head,-1,sizeof(head)); memset(degree,0,sizeof(degree)); memset(vist,0,sizeof(vist)); cnt=ans=0; for(int i=1;i<=p;i++) scanf("%d",&pond[i]); for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); degree[u]++; degree[v]++; } //搜索度数为1的池塘 for(int i=1;i<=p;i++) if(degree[i]==1) dfs(i); //统计结果 for(int i=1;i<=p;i++) { if(degree[i]&&!vist[i]) { sum=pond[i]; num=1; dfs2(i); if(num%2) ans+=sum; } } printf("%lld\n",ans); } return 0; }
解法二:
bfs+dfs
代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> #include <queue> using namespace std; int pond[10010]; struct edge { int next,to; }store[200010]; int head[10010],cnt,degree[10010]; bool vist[10010],cut_off[200010]; long long sum; int num; queue <int> qe; inline void addedge(int a,int b) { store[cnt].to=b; store[cnt].next=head[a]; head[a]=cnt++; } void bfs() { int tmp,cur,v; while(!qe.empty()) { cur=qe.front(); qe.pop(); tmp=head[cur]; while(~tmp) { v=store[tmp].to; if(degree[v]) { cut_off[tmp]=cut_off[tmp^1]=1; degree[v]--; if(degree[v]==1) { qe.push(v); degree[v]=0; } } tmp=store[tmp].next; } } } void dfs(int x) { int tmp,v; vist[x]=1; tmp=head[x]; while(tmp!=-1) { if(!cut_off[tmp]) { v=store[tmp].to; if(!vist[v]) { num++; sum+=pond[v]; dfs(v); } } tmp=store[tmp].next; } } int main() { int t,p,m,u,v; long long ans; scanf("%d",&t); while(t--) { scanf("%d%d",&p,&m); memset(head,-1,sizeof(head)); memset(degree,0,sizeof(degree)); memset(vist,0,sizeof(vist)); memset(cut_off,0,sizeof(cut_off)); cnt=0,ans=0; for(int i=1;i<=p;i++) scanf("%d",&pond[i]); for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); degree[u]++; degree[v]++; } for(int i=1;i<=p;i++) if(degree[i]==1) qe.push(i),degree[i]=0; bfs(); for(int i=1;i<=p;i++) { if(degree[i]&&!vist[i]) { sum=pond[i]; num=1; dfs(i); if(num%2) ans+=sum; } } printf("%lld\n",ans); } return 0; }