HDU - 4619 Warm up 2

来源:互联网 发布:网络层通过什么通信 编辑:程序博客网 时间:2024/05/22 06:18

练习赛打完,看网上的题解都是最大匹配。 。 。 。


思路:

把一个骨牌当成是一条边,两端分别是两个点,然后建图。那么问题就转换成求最多剩下多少条边互不相交。

然后求连通分量,两个连通分量之间不会有边。一个连通分量内,取完后最优的结果一定是每个点都在一条边上(奇数个点会有一个点不在边上),所以有k个点,就会剩下k/2条边。

也就是只需要计算每个连通分量的大小就好。


#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <vector>using namespace std;const int maxn=4000+10;int bcc[maxn];vector<int> G[maxn];int g[111][111];int N, M, n;int cnt, bcc_num[maxn];void dfs(int u, int num){    bcc_num[u]=num;    bcc[num]++;    for(int i=0; i<G[u].size(); i++)        if(!bcc_num[G[u][i]])            dfs(G[u][i], num);}void solve(){    cnt=0;    memset(bcc_num, 0, sizeof(bcc_num));    for(int i=1; i<=n; i++)        if(!bcc_num[i])        {            bcc[++cnt]=0;            dfs(i, cnt);        }    int ans=0;    for(int i=1; i<=cnt; i++)        ans+=bcc[i]/2;    printf("%d\n", ans);}int main(){    while(~scanf("%d%d", &N, &M) && N+M)    {        memset(g, 0, sizeof(g));        for(int i=0; i<maxn; i++)            G[i].clear();        n=0;        while(N--)        {            int x, y, u, v;            scanf("%d%d", &x, &y);            if(!g[x][y])            {                g[x][y]=++n;                u=n;            }            else u=g[x][y];            if(!g[x+1][y])            {                g[x+1][y]=++n;                v=n;            }            else v=g[x+1][y];            G[u].push_back(v);            G[v].push_back(u);        }        while(M--)        {            int x, y, u, v;            scanf("%d%d", &x, &y);            if(!g[x][y])            {                g[x][y]=++n;                u=n;            }            else u=g[x][y];            if(!g[x][y+1])            {                g[x][y++]=++n;                v=n;            }            else v=g[x][y+1];            G[u].push_back(v);            G[v].push_back(u);        }        solve();    }    return 0;}

0 0
原创粉丝点击