现在的位置: 首页 > 综合 > 正文

HDOJ 3360 – National Treasures 二分图的最小点覆盖

2013年04月27日 ⁄ 综合 ⁄ 共 1704字 ⁄ 字号 评论关闭

               题意:

                       在R*C上有些艺术品..每个艺术品用非负数表示代表他附近那些格子需要保安...-1代表该格子上本来就是保安..必须保证艺术品关键的位置必须要有保安.或者不放这个艺术品..在这个艺术品上站保安..问最少要增加多少保安满足条件...

               题解:

                       根据每件艺术品所需要的安保条件建边..注意..这个边的意思是两个点需要联系..所以艺术品指向保安和保安指向艺术品是一回事...题目就转化成了二分图的最小点覆盖问题(用最少的点覆盖所有的边..边是需要的安保关系..点是需要增加的保安数量)...等价于求其最大匹配...注意..建图有两种方式..一种是分奇偶点..建成两侧完全不同的点..答案就是跑最大匹配..第二种是两侧都是相同的点..边也是建双向边..答案是最大匹配/2

Program:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<stack>
#include<string.h>
#include<queue>
#define ll long long
#define esp 1e-5
#define MAXN 3005
#define MAXM 500005
#define oo 100000007
using namespace std;    
struct node
{
       int y,next;
}line[MAXM];
int match[MAXN],way[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 Lnum,_next[MAXN],arc[MAXN][MAXN];
bool used[MAXN];
void addline(int x,int y)
{
       line[++Lnum].next=_next[x],_next[x]=Lnum,line[Lnum].y=y;
}
bool dfs(int x)
{
       for (int k=_next[x];k;k=line[k].next)
       {
               int y=line[k].y;
               if (used[y]) continue;
               used[y]=true;
               if (!match[y] || dfs(match[y]))
               {
                     match[y]=x;
                     return true;
               }
       } 
       return false;
}
int getmax(int n)
{
       int sum=0;
       memset(match,0,sizeof(match));
       for (int i=0;i<n;i++)
       {
                memset(used,false,sizeof(used));
                sum+=dfs(i);
       }
       return sum;
}
int main()
{            
       int i,cases=0,R,C,x,y,h;
       freopen("input.txt","r",stdin);
       freopen("output.txt","w",stdout);
       while (~scanf("%d%d",&R,&C) && R)
       { 
               for (y=0;y<R;y++)
                  for (x=0;x<C;x++) 
                     scanf("%d",&arc[y][x]);
               Lnum=0,memset(_next,0,sizeof(_next));
               for (y=0;y<R;y++)
                  for (x=0;x<C;x++)
                  if (arc[y][x]>0)
                  { 
                         h=arc[y][x]; 
                         for (i=0;i<12;i++)
                            if (h&(1<<i))
                            {
                                   int yy=y+way[i][0],xx=x+way[i][1];
                                   if (xx<0 || yy<0 || xx>=C || yy>=R || arc[yy][xx]<0) continue;
                                   addline(y*C+x,yy*C+xx),addline(yy*C+xx,y*C+x);
                            }
                  }
               printf("%d. %d\n",++cases,getmax(R*C)/2);
       }    
       return 0;  
}  
/*
3 4
0    0   512  0
536  512 0    0
0    0   512  0
3 4
0    0   0  0
512  536 0  0
0    0   0  0
0 0

3
1
*/

抱歉!评论已关闭.