HDU 3360-National Treasures(最小点覆盖+奇偶匹配)

/*******************************************************

    题意:
    现在有一个n*m的博物馆g,每一个g[i][j]要不是一个<=2^12
    的数,要不就是-1。
    如果这个点是-1,表示这个点有一个守卫
    否则就是以g[i][j]为关键字规则的宝物。

    具体规则是:
    现在有12个被编号的点(题目中给出了图片),然后把g[i][j]表示成一个12位二进制数
    ,从低位到高位(右到左)依次为1~12,如果某位i上是1,就表示在编号
    为i的相对位置放置一个守卫的话,这个宝物就能被保护了
    守卫可以移走一个宝物自己代替那个格子,但不允许仅仅移走宝物

    问最少需要再额外添加几个守卫使得未被移走的宝物都被保护

    思路:
    从图片中可看出,编号相对位置的都是马步位置和相邻位置,也就是说
    其i+j的奇偶性必定与宝物的i+j的奇偶性不同,显然想到奇偶匹配

    以奇点为集合A,偶点为集合B,A->B建边,如果中心点(i,j)的关键位置中
    包含相对位置(x,y)点,那么就g[(i-1)*m+j].push_back((x-1)*m+y);
    要注意如果中心点(i,j)的关键位置不包含(x,y)而(x,y)的关键位置包含(i,j)
    也建立一条以上的边。
    如果遇到关键位置上已经有守卫了,即mp[x][y] == -1,那就不要加边了(因为
    最后求的是最小点覆盖,不加边就不需要考虑覆盖这条边了)

    最后求最小点覆盖就行了

********************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "list"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
#include "set"
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)
#define FR (freopen("in.txt","r",stdin))
#define clr(a,b) memset(a,b,sizeof(a))
#define lowbit(t) (t&-t)
#define PI acos(-1.0)
#define mkp make_pair
using namespace std;
typedef long long LL;
const int MAXN = 2500+100;
const int inf = 522133279;
const int mod = 1000000007;

int cx[MAXN],cy[MAXN];
int vis[MAXN];
vector<int> g[MAXN];
int mp[100][100];
int n,m;

int dir[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 duicheng[] = {4,5,6,7,0,1,2,3,10,11,8,9};

int path(int u)
{
    for(int i = 0 ; i < g[u].size() ; i++)
    {
        int v = g[u][i];
        if(!vis[v])
        {
            vis[v]=1;
            if(cy[v] == -1 || path(cy[v]))
            {
                cx[u]=v;
                cy[v]=u;
                return 1;
            }
        }
    }
    return 0;
}

int maxMatch()
{
    int res=0;
    clr(cx,-1);
    clr(cy,-1);

    for(int i = 1 ; i <= n*m ; i++)
    {
        if(cx[i] == -1)
        {
            clr(vis,0);
            res += path(i);
        }
    }
    return res;
}

bool border(int x , int y)
{
    return (x>=1&&x<=n)&&(y>=1&&y<=m);
}

int main()
{
    int ka=0;
    while(~scanf("%d%d",&n,&m),n+m)
    {
        for(int i = 0 ; i < MAXN ; i++)
            g[i].clear();
        for(int i = 1 ; i <= n ; i++)
            for(int j = 1 ; j <= m ; j++)
                scanf("%d",&mp[i][j]);

        for(int i =1 ; i <= n ; i++)
            for(int j = 1 ; j <= m ; j++)
            {
                if((i+j)%2 && mp[i][j]!=-1)         //对于奇点建边
                {
                    for(int k = 0 ; k < 12 ; k++)
                    {
                        int x = i+dir[k][0];
                        int y = j+dir[k][1];

                        if(!border(x,y) || mp[x][y] == -1)
                            continue;

                        if((1<<k)&mp[i][j])
                            g[(i-1)*m+j].push_back((x-1)*m+y);
                        if((1<<duicheng[k]) & mp[x][y])
                            g[(i-1)*m+j].push_back((x-1)*m+y);
                    }
                }
            }
        printf("%d. %d\n",++ka,maxMatch());

    }
    return 0;
}

HDU 3360-National Treasures(最小点覆盖+奇偶匹配)

时间: 2024-12-27 21:07:09

HDU 3360-National Treasures(最小点覆盖+奇偶匹配)的相关文章

HDU 3360 National Treasures 奇偶匹配最小点覆盖

题目来源:HDU 3360 National Treasures 题意:如果a[i][j] != -1 把他转成二进制 最多有12位 代表题目那张图的12个位置 如果对应位是1 说明在那里放一个守卫可以看住a[i][j]位置上的这个东西 思路:明显死最小点覆盖 奇偶匹配建图 #include <cstdio> #include <cstring> #include <vector> using namespace std; const int maxn = 55; in

HDU 3360 National Treasures 奇偶匹配的最低点覆盖

标题来源:pid=3360">HDU 3360 National Treasures 意甲冠军:假设a[i][j] != -1 把他转成二进制 最多有12位 代表题目那张图的12个位置 假设相应位是1 说明在那里放一个守卫能够看住a[i][j]位置上的这个东西 思路:明显死最小点覆盖 奇偶匹配建图 #include <cstdio> #include <cstring> #include <vector> using namespace std; con

HDU 3360 National Treasures

National Treasures Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 3   Accepted Submission(s) : 1 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description The great hall of th

HDU 1054 Strategic Game 最小点覆盖

 最小点覆盖概念:选取最小的点数覆盖二分图中的所有边. 最小点覆盖 = 最大匹配数. 证明:首先假设我们求的最大匹配数为m,那么最小点覆盖必然 >= m,因为仅仅是这m条边就至少需要m个点.然后假如我们已经求得最小覆盖点集,那么在点集中每个点必然有着这样的性质,在于它相连的边里面,一定有一条边的端点不在最小点集中,因为如果连一条这样的边都没有,那这个点完全没有在最小点集的必要,我们任意选取这样的一条边,一定可以形成一个匹配,匹配数与最小点集中的点的个数相等,但现在这仅仅是一个匹配,他必然小于最大

hdu 1054 Strategic Game 二分图最小点覆盖

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1054 题意: 给出一个无向图,求最小点覆盖. 思路: 用网络流来做设立一个超级源点和一个超级汇点. 每个点拆成i和i'. 从超级源点向点i连一条边,容量为1. 从i’向超级汇点连一条边,容量为1. 从i向i'连一条边,容量为正无穷. 然后求最小割/2.因为拆点拆成了2个. 也可以用二分图匹配来做,也是求出最大匹配然后/2. 1 #include <bits/stdc++.h> 2 using na

hdu 1151 或 poj 1422 二分图 最小点覆盖集

最小点覆盖集的裸题,只要“拆点建边”然后求出最大匹配,则:最小点覆盖集的大小 = 点数 - 最大匹配 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 121; 7 const int M = 5000; 8 bool visit[N]; 9 int mark[N]; 10 int head[N]; 11 int

UVA 11419 - SAM I AM(二分图匹配+最小点覆盖)

UVA 11419 - SAM I AM 题目链接 题意:给定一个棋盘,上面有一些目标,现在要放炮,一个炮能打一行或一列,问最少放几个炮及放炮位置 思路:首先是二分图匹配,每个目标行列建边,做二分图匹配就是最少的放炮位置,至于输出方案,利用最小点覆盖的Konig原理去做,详细证明 代码: #include <cstdio> #include <cstring> #include <vector> using namespace std; const int N = 10

HDU 1498 50 years, 50 colors(最小点覆盖,坑题)

50 years, 50 colors Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1635    Accepted Submission(s): 892 Problem Description On Octorber 21st, HDU 50-year-celebration, 50-color balloons floating

HDU 1498 50 years, 50 colors(二分最大匹配之最小点覆盖)

题目地址:HDU 1498 晕啊...三个人同时做的这个题,结果全都理解错意思了..而且每个人理解错的地方还都不一样..但是样例还都能过,...简直炫酷... 题意:n*n的矩阵放置不同的颜色(不同的数字代表不同的颜色),你有k次选择,每一次只能选择某一行或某一列,可以消除该行(列)的所有颜色,问有哪几种颜色,无论怎样经过k次选择后依然无法完全抹去. 这个题的思路就是分别求出每种颜色的最少操作次数.然后只要大于k次的就是不符合要求的.然后输出就行了. #include <iostream> #