zoukankan      html  css  js  c++  java
  • hdu3360+二分匹配(匈牙利算法)

    有一个展厅,里面有一些文物和守卫,现在守卫不够,需要再雇佣一些守卫使所有文物被保护,且雇佣数量要最少,求这个数量。

    文物被保护的定义:这个文物的所有必须被保护的点都要有守卫。

                              一个文物由一个2的12次方以内的数表示,那么这个数最多有12位,对应图中给出打的12个可能要被保护的点。

                              从末位(i=0 to 11)开始,当i为1,则对应图中12个点中的第(i+1)个点必须被保护。

    构图:我们遍历每个文物,求出每个文物的必须被保护的点,向这个点与其对应的文物之间加边。

            显然,当图中每条边至少有一个点是有守卫的点,那么此时所有文物都被保护了。这便是求一个二分图的最小点覆盖,也即最大匹配数。

    细节:此题用邻接矩阵可能会超时或爆内存。可用邻接表。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<vector>
     4 using namespace std;
     5 int n,m;
     6 int dx[12]= {-1,-2,-2,-1,1,2,2,1,-1,0,1,0};
     7 int dy[12]= {-2,-1,1,2,2,1,-1,-2,0,1,0,-1};
     8 int a[60][60],linker[3600],vis[3600];
     9 vector<int> v[2550];
    10 bool dfs(int u)
    11 {
    12     int kk;
    13     for(kk=0;kk<v[u].size();kk++)
    14     {
    15         int vv=v[u][kk];
    16         if(!vis[vv])
    17         {
    18             vis[vv]=1;
    19             if(linker[vv]==-1||dfs(linker[vv]))
    20             {
    21                 linker[vv]=u;
    22                 return true;
    23             }
    24         }
    25     }
    26     return false;
    27 }
    28 int main()
    29 {
    30     int i,j,k,numcas=0;
    31     while(scanf("%d%d",&n,&m)!=EOF)
    32     {
    33         if(n==0&&m==0) break;
    34         for(i=0;i<n*m;i++)
    35             v[i].clear();
    36         for(i=0;i<n;i++)
    37             for(j=0;j<m;j++)
    38             scanf("%d",&a[i][j]);
    39         for(i=0;i<n;i++)
    40         {
    41             for(j=0;j<m;j++)
    42             {
    43                 if(a[i][j]!=-1)
    44                 {
    45                     for(k=0;k<12;k++)
    46                     {
    47                         if((a[i][j]>>k)&1)
    48                         {
    49                             int xx=i+dx[k];
    50                             int yy=j+dy[k];
    51                             if(xx>=0&&xx<n&&yy>=0&&yy<m&&a[xx][yy]!=-1)
    52                             {
    53                                 int p1=i*m+j;
    54                                 int p2=xx*m+yy;
    55                                 v[p1].push_back(p2);
    56                                 v[p2].push_back(p1);
    57                             }
    58                         }
    59                     }
    60                 }
    61             }
    62         }
    63         memset(linker,-1,sizeof(linker));
    64         int u,ret=0;
    65         for(u=0;u<n*m;u++)
    66         {
    67             memset(vis,0,sizeof(vis));
    68             if(dfs(u)) ret++;
    69         }
    70         printf("%d. %d
    ",++numcas,ret/2);
    71     }
    72     return 0;
    73 }
  • 相关阅读:
    小球下落
    生成1~n的排列
    hdu1871无题
    android本地定时通知
    php 5.3起弃用session_register
    centos 6.3 编译安装 nginx +mysql + php
    skynet网络库socketserver
    mac下通过docker搭建LEMP环境
    Git操作
    iOS本地通知
  • 原文地址:https://www.cnblogs.com/mt522/p/5356643.html
Copyright © 2011-2022 走看看