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

来源:互联网 发布:淘宝摩托车准备店铺 编辑:程序博客网 时间:2024/05/29 19:06
/*******************************************************    题意:    现在有一个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_pairusing 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;}

0 0