HDU 4619 Warm up 2

转载请注明出处忆梦http://blog.csdn.net/fjy4328286/article/details/9534955


题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4619


题目大意:输入n m, n代表横着的多米诺骨牌个数, m代表竖着的多米诺骨牌个数。

                  输入n个点,x y  代表(x,y)和(x+1,y)处为横着的多米诺骨牌覆盖的点

                  输入m个点,x y 代表(x,y)和(x,y+1)处为竖着的多米诺骨牌覆盖的点

  题目中还有一个重要的条件,只有横着的多米诺骨牌和竖着的多米诺骨牌还可能互相覆盖,所以一个点最多被覆盖两次(横着竖着分别一次)。


题解:比赛的时候就想用并查积来写,但是不知道思路会不会有错,就没有敲。  赛后试了一下,果然A了。思路很简单,将每一条链上的点归为一堆(用并查集来实现),将链上的点数统计一下个数,然后再除以2就是这条链应该有的边数。将矩阵中所有链按上述方法来算边数,最后求边数和就行了。



#include<cstdio>  
#include<iostream>  
#include<vector>  
using namespace std;  
  
#define N 2050  
#define MAXN 105  
int F[N];     
int fun(int x)  
{  
    if(F[x] != x)  
        F[x] = fun(F[x]);  
    return F[x];  
}  
  
int main ()  
{  
    int n, m;  
    while(scanf("%d %d", &n, &m), (n||m))  
    {     
        int i, j, k;  
        for(i = 1; i <= n+m; i++)  
            F[i] = i;  
          
        vector<int>s[MAXN][MAXN];  
          
        int a,b;  
        for(i = 1; i <= n; i++)  
        {  
            scanf("%d %d", &a, &b);  
            s[a][b].push_back(i);  
            s[a+1][b].push_back(i);  
        }  
        for(i = n + 1; i <= n+m; i++)  
        {  
            scanf("%d %d", &a, &b);  
            s[a][b].push_back(i);  
            s[a][b+1].push_back(i);  
        }  
          
        for(i = 0; i < MAXN; i++)  
            for(j = 0; j < MAXN; j++)  
            {  
                if(s[i][j].size() == 2)  
                {  
                    a = s[i][j][0];  
                    b = s[i][j][1];  
                    a = fun(a);  
                    b = fun(b);  
                    if(a != b)  
                        F[a] = b;  
                }  
            }  
            int root[N], it = 0;  
            int cnt[N];  
              
            memset(cnt, 0 ,sizeof(cnt));  
             
              
            for(i = 0; i < MAXN; i++)  
                for(j = 0; j < MAXN; j++)  
                {  
                    if(s[i][j].size() != 0)  
                    {  
                        int temp = fun(s[i][j][0]);  
                        for(k = 0; k <= it; k++)  
                            if(temp == root[k])  
                                break;  
                            if(k > it)  
                            {   cnt[it]++;root[it++] = temp;}  
                            else  
                                cnt[k]++;  
                    }  
                      
                }  
                int ans = 0;  
                for(i = 0; i < N; i++)  
                    ans += cnt[i]/2;  
                  
                printf("%d\n", ans);  
                  
    }  
    return 0;  
}  






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值