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\n",++numcas,ret/2);
71     }
72     return 0;
73 }

 

posted @ 2016-04-05 20:21  2014551532  阅读(158)  评论(0编辑  收藏  举报