题意:
几个无向图,将各无向图删除子节点,将无向图变成连通图,并求出点数是奇数的连通图的节点的值的和。
输入:
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
分析:
要想解决图论的问题,首先要明确图的节点的属性,该题的节点属性:权值,由于要删去子节点,所以加上与其他点的连接数量
num,还有一个就是点的位置,方便建图的时候。之后在dfs遍历图的时候,求和并且统计节点的个数。之后就是构图过程,建立两
个节点的关联关系,将不满足的条件的节点删去,注意再删除节点的时候,既要删除值,又要删除关联关系。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
typedef long long LL;
LL sum,val,num2,ans=0,p,mm;
int T,f=0,vis[10005];
struct node
{
int v; //节点的值
int num; //一个节点连接的其他节点的数量
vector <int> pos; //表示节点的位置关系
} m[10005];
int dfs(int a) //dfs遍历连通图,统计节点的个数和求值的和
{
sum+=m[a].v;
num2++;
vis[a]=1;
for(int i=0; i<m[a].pos.size(); i++)
{
int tmp=m[a].pos[i];
if(vis[tmp]==0&&m[tmp].v!=0)
dfs(tmp);
}
return num2;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%I64d%I64d",&p,&mm);
for(int i=1; i<=p; i++)
{
scanf("%d",&val);
m[i].v=val;
m[i].num=0;
m[i].pos.clear();
}
for(int i=1; i<=mm; i++)
{
int aa,bb;
scanf("%d%d",&aa,&bb);
m[aa].pos.push_back(bb); //建图
m[aa].num++;
m[bb].pos.push_back(aa);
m[bb].num++;
}
while(1)
{
f=0;
for(int i=1; i<=p; i++)
{
if(m[i].v!=0&&m[i].num<2)
{
f=1;
m[i].v=0; //删除点的值
for(int j=0; j<m[i].pos.size(); j++) //删除点与其他点的线
{
int tmp=m[i].pos[j];
m[tmp].num--;
}
}
}
if(f==0) //若是都满足条件跳出
break;
}
ans=0;
memset(vis,0,sizeof(vis));
for(int i=1; i<=p; i++)
{
if(vis[i]==0&&m[i].v!=0)
{
sum=0;
num2=0;
LL s=dfs(i);
if(s%2==1)
ans+=sum;
}
}
printf("%I64d\n",ans);
}
return 0;
}
小结: