这是一道水题,
这里是最大流解法,之后再补
坑在又忘了反向建边了
题意:给你二维bool数组,让你求出能用多米诺骨牌覆盖所有 1 且骨牌最少的放法(因为多米诺骨牌1*2的结构方便描述,原题没有),原本的数据是字符数组,'*'为1,'o'为0,
思路:仔细看看题会发现是上下左右只能取一个,不是那种十字星形的
取的话只能取一个点或者是两个点,要是把棋盘染色一定只能取一黑一白,总'*'也就是1的数目-黑到白的路数=孤立点+黑到白的边数=总数-最大匹配
#include <cstdio> #include <cstring> #include <vector> using namespace std; char maz[62][62]; int e[500][500]; int d[4][2]={0,1,0,-1,1,0,-1,0}; int n,m; vector <int > G[500]; bool vis[500]; void addedge(int from,int to){ e[from][to]=1; G[from].push_back(to); } int dfs(int s){ vis[s]=true; if(s==n*m+1){//printf("dfs %d ok\n",s); return 1;} for(int i=0;i<G[s].size();i++){ if(!vis[G[s][i]]&&e[s][G[s][i]]&&dfs(G[s][i])){ e[s][G[s][i]]=0; e[G[s][i]][s]=1; // printf("dfs %d ok\n",s); return 1; } } //printf("dfs %d failed \n",s); return 0; } int maxflow(){ int ans=0,f; while(1){ f=dfs(n*m); memset(vis,0,sizeof(vis)); if(f==0)break; ans+=f; } return ans; } void printe(){ for(int i=0;i<m*n+2;i++){ bool f=false; for(int j=0;j<m*n+2;j++){ if(e[i][j]){printf("e[%d][%d] ",i,j);f=true;} } if(f) printf("\n"); } } int main(){ int t; scanf("%d",&t); while((t--)&&scanf("%d%d",&n,&m)==2){ for(int i=0;i<=n*n+1;i++){G[i].clear();} memset(e,0,sizeof(e)); for(int i=0;i<n;i++){ scanf("%s",maz[i]); } int ans=0; int star=0; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ if(maz[i][j]=='*'){ star++; if((i+j)&1){ addedge(n*m,i*m+j);//n*n s n*n+1 t // printf("addedge %d %d %d %d:%d to %d\n",n,0,i,j,n*m,i*m+j); for(int k=0;k<4;k++){ int nx=i+d[k][0]; int ny=j+d[k][1]; if(nx>=0&&nx<n&&ny>=0&&ny<m&&maz[nx][ny]=='*'){ addedge(i*m+j,nx*m+ny); // printf("addedge %d %d %d %d:%d to %d\n",i,j,nx,ny,i*m+j,nx*m+ny); } } } else { addedge(i*m+j,n*m+1); //printf("addedge %d %d %d %d:%d to %d\n",i,j,n,1,i*m+j,n*m+1); for(int k=0;k<4;k++){ int nx=i+d[k][0]; int ny=j+d[k][1]; if(nx>=0&&nx<n&&ny>=0&&ny<m&&maz[nx][ny]=='*'){ addedge(i*m+j,nx*m+ny); e[i*m+j][nx*m+ny]=0; // printf("addedge %d %d %d %d:%d to %d\n",i,j,nx,ny,i*m+j,nx*m+ny); } } } } } } ans=maxflow(); printf("%d\n",star-ans); } return 0; }