) are always a subset of the 12 neighboring cells as shown in the grid below.

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;}
新聞熱點
疑難解答