1 3512 -1 20482 3512 2560 2048512 2560 20480 0 Sample Output1. 02. 2HintThe picture below shows the solution of the second test case where the two artifacts in the middle are replaced by guards.题目大意:
给你一个n*m的矩阵,在该矩阵中放置一些警卫,每个警卫所能守卫的格子为他的二进制中1的位置如上图,编号1到12分别表示第i位为1所能守卫的格子,矩阵中除了警卫和值为-1外都是文物然后问你最少放多少个警卫才能守住所有的文物
题目思路:
首先我们考虑怎么建图,我知道每个警卫所能守卫的格子,我们不妨先将二维坐标转换成一维坐标,然后每个守卫与他所能守卫的格子连边,这样我们就转换成了求最少的点使得所有的边的至少一个端点被选中,即最小点覆盖模型,所以我们只需进行最大匹配就行
AC代码:
#include<cstring>#include<cstdio>#include<vector>const int maxn = 55;using std::vector;int mp[maxn][maxn],link[maxn*maxn];bool vis[maxn*maxn];vector<int>v[maxn*maxn];int n,m;int fx[14][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}; //记录12个方向bool dfs(int u){ for(int i=0;i<v[u].size();i++){ int vv = v[u][i]; if(!vis[vv]){ vis[vv]=true; if(link[vv]==-1||dfs(link[vv])){ link[vv]=u; return true; } } } return false;}int main(){ int T=1; while(scanf("%d%d",&n,&m),n+m){ memset(v,0,sizeof(v)); memset(link,-1,sizeof(link)); 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(mp[i][j]!=-1) for(int k=0;k<12;k++) //枚举12个方向 if((mp[i][j]>>k)&1){ //状态位为1 int h = i+fx[k][0],l=j+fx[k][1]; if(h>=1&&h<=n&&l>=1&&l<=m&&mp[h][l]!=-1){ int x = (i-1)*m+j,y=(h-1)*m+l; v[x].push_back(y); v[y].push_back(x); } } int ans = 0; for(int i=1;i<=n*m;i++){ memset(vis,false,sizeof(vis)); if(dfs(i))ans++; } printf("%d. %d/n",T++,ans/2); } return 0;}
新闻热点
疑难解答