FZU 2112 Tickets

这个问题可以转变一下,先要知道有几个连通块,连通块之间肯定需要添加一条边,

还需要知道每个连通块内部需要添加几条边,这个问题等价于求一张图至少需要几笔画成,这个问题的答案是度为奇数的点的个数/2

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn=100000+10;
int T;
int n,m;
vector<int>G[maxn];
int tot[maxn];
bool flag[maxn];
bool flag2[maxn];
int q[maxn],sum;
int ans;

void init()
{
    ans=0;
    memset(tot,0,sizeof tot);
    memset(flag,0,sizeof flag);
    memset(flag2,0,sizeof flag2);
}

void read()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) G[i].clear();
    for(int i=1;i<=m;i++)
    {
        int u,v; scanf("%d%d",&u,&v);
        tot[u]++;tot[v]++;
        flag2[u]=1;flag2[v]=1;
        G[u].push_back(v);
        G[v].push_back(u);
    }
}

void dfs(int now)
{
    flag[now]=1; q[sum++]=now;
    for(int i=0;i<G[now].size();i++)
        if(!flag[G[now][i]])
            dfs(G[now][i]);
}

void work()
{
    for(int i=1;i<=n;i++)
    {
        if(!flag[i]&&flag2[i])
        {
            sum=0; ans++; dfs(i);
            int tmp=0;
            for(int j=0;j<sum;j++) if(tot[q[j]]%2==1) tmp++;
            ans=ans+(tmp-1)/2;
        }
    }
    ans--;
    printf("%d\n",ans);
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        init();
        read();
        work();
    }
    return 0;
}

 

你可能感兴趣的:(FZU 2112 Tickets)