加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

HDU 3360 最小点覆盖

(2010-07-28 18:38:49)
标签:

hdu

3360

最小点覆盖

it

分类: 图论

二分图中,选取最少的点数,使这些点和所有的边都有关联(把所有的边的覆盖),叫做最小点覆盖。
最少点数=最大匹配数
举例:
图中有AB两组不相交的点。
A中的每个点需要B中的某些点同时来看守。
B中的每个点需要A中的某些点同时来看守。
选择最少的点,使所有的点都被看守。
A需要B中的点看守,则AB间相应的点连接。每条边就表示一个看守条件。
就是选择一些点,满足所有的边:和所有的边都有关联。
解之。
题目:HDU 3360
题目描述:
给你一个图,图中有宝物和保安两种元素。
每个宝物需要周围的某些位置同时安放保安(如果那些位置有宝物,可以把宝物替换成保安)
问你最少需要再安置多少保安,可以使所有宝物满足要求。
解题报告:
假设宝物坐标为i,j,可以发现,它需要安放保安的位置的坐标x,y,奇偶性不一样,即
(i + j) % 2 != (x + y) % 2。
这样,就可以按坐标之和的奇偶性把图分成两部分A,B,按照上述方法,解之。
代码如下:

#include<iostream>
#include<vector>
using namespace std;
#define SIZE 1400
int match[SIZE], x[60][60], mmp[SIZE][SIZE];
bool vst[SIZE], gg[SIZE][SIZE];
vector<int> g[SIZE];
int n, m;
int find(int u)
{
    for(int i = 0; i < g[u].size(); i++)
        if (!vst[g[u][i]])
        {
            vst[g[u][i]] = 1;
            if (match[g[u][i]] == -1 || find(match[g[u][i]]) == 1)
            {
                match[g[u][i]] = u;
                return 1;
            }
        }
    return 0;
}
int solve()
{
    memset(match, -1, sizeof(match));
    int ans = 0;
    for(int i = 0; i < n; i++)
    {
        memset(vst, 0, sizeof(vst));
        ans += find(i);
    }
    return ans;
}
int move[12][2] = {{-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}, {1, 2}, {2, 1}, {2, -1}, {1, -2}, {-1, 0}, {0, 1}, {1, 0}, {0, -1}};
int r, c, cnt;
void judge(int a, int b, int cc, bool flag)
{
    for(int i = 0; i < 12; i++)
    {
        if ((cc >> i) & 1)
        {
            int tempa = a + move[i][0], tempb = b + move[i][1];
            if (tempa >= 0 && tempa < r && tempb >= 0 && tempb < c && x[tempa][tempb] != -1)
            {
                if (flag) g[mmp[a][b]].push_back(mmp[tempa][tempb]);
                else g[mmp[tempa][tempb]].push_back(mmp[a][b]);
            }
        }
    }
}
int main()
{
    cnt = 1;
    while(scanf("%d%d", &r, &c) && (r || c))
    {
        for(int i = 0; i < r; i++)
            for(int j = 0; j < c; j++)
                scanf("%d", &x[i][j]);
        n = (r * c) / 2;
        m = r * c - n;
        for(int i = 0; i < n; i++) g[i].clear();
        n = m = 0;
        for (int i=0;i<r;i++)
   for (int j=0;j<c;j++)
    if (x[i][j]!=-1)
    {
     if ((i+j)%2==1) mmp[i][j]=n++;
     else mmp[i][j]=m++;
    }
        for(int i = 0; i < r; i++)
            for(int j = 0; j < c; j++)
                if (x[i][j] != -1)
                    judge(i, j, x[i][j], (i + j) % 2);
        printf("%d. %d\n", cnt++, solve());
    }
    return 0;
}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有