您的位置:首页 > 其它

hdu3360+二分匹配(匈牙利算法)

2016-04-05 20:21 309 查看
有一个展厅,里面有一些文物和守卫,现在守卫不够,需要再雇佣一些守卫使所有文物被保护,且雇佣数量要最少,求这个数量。

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

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

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

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

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

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

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
int n,m;
int dx[12]= {-1,-2,-2,-1,1,2,2,1,-1,0,1,0};
int dy[12]= {-2,-1,1,2,2,1,-1,-2,0,1,0,-1};
int a[60][60],linker[3600],vis[3600];
vector<int> v[2550];
bool dfs(int u)
{
int kk;
for(kk=0;kk<v[u].size();kk++)
{
int vv=v[u][kk];
if(!vis[vv])
{
vis[vv]=1;
if(linker[vv]==-1||dfs(linker[vv]))
{
linker[vv]=u;
return true;
}
}
}
return false;
}
int main()
{
int i,j,k,numcas=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0) break;
for(i=0;i<n*m;i++)
v[i].clear();
for(i=0;i<n;i++)
for(j=0;j<m;j++)
scanf("%d",&a[i][j]);
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
if(a[i][j]!=-1)
{
for(k=0;k<12;k++)
{
if((a[i][j]>>k)&1)
{
int xx=i+dx[k];
int yy=j+dy[k];
if(xx>=0&&xx<n&&yy>=0&&yy<m&&a[xx][yy]!=-1)
{
int p1=i*m+j;
int p2=xx*m+yy;
v[p1].push_back(p2);
v[p2].push_back(p1);
}
}
}
}
}
}
memset(linker,-1,sizeof(linker));
int u,ret=0;
for(u=0;u<n*m;u++)
{
memset(vis,0,sizeof(vis));
if(dfs(u)) ret++;
}
printf("%d. %d\n",++numcas,ret/2);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: