题意:给你一个m*n(1<=m,n<=50)的图,其中 ‘#’代表冰山, ‘*’代表海洋, ‘o’代表浮冰。。然后让你尽可能放置最多的船,但是要满足一下规矩:
- 船不能放在冰山上;
- 船不能放到浮冰上
- 两艘船之间除非中间有冰山,否则不能在同一列或同一行。
分析:红果果的二分最大匹配。。。。图也很容易构造。。。把每一行被冰山分隔开来的海洋格子连通块(至少一个格子)作为X点,同样的每一列被冰山分隔开来的海洋格子连通块作为Y点,X点与Y点有边相连当且仅当这两个连通块共用一个海洋格子。然后跑二分最大匹配。。。2500个点,妥妥的。
以好像是官方题解,但过不了,把next数组改成nextt能过c++的,过不不了g++。
#include<stdlib.h> #include<cmath> #include<cstring> #include<iostream> #include<map> #include<set> #include<algorithm> #include<queue> #include<vector> #include<cstdio> using namespace std; #define N 205 #define M 50005 int ev[M],nextt[M]; int head[M]; int cnt; bool vis[M]; int pre[M]; char s[N][N]; int x[N][N],y[N][N]; int pn[2]; void addedge(int u,int v){ ev[cnt]=v; nextt[cnt]=head[u]; head[u]=cnt++; return; } int find(int x){ for(int i=head[x];~i;i=nextt[i]){ int v=ev[i]; if(!vis[v]){ vis[v]=1; if(pre[v]==-1||find(pre[v])) { pre[v]=x; return 1; } } } return 0; } int main() { int t; scanf("%d",&t); while(t--){ int n,m; memset(head,-1,sizeof(head)); cnt=0; memset(pre,-1,sizeof(pre)); memset(x,0,sizeof(x)); memset(y,0,sizeof(y)); scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%s",s[i]); int num=0; for(int i=0;i<n;i++) { bool flag=0; for(int j=0;j<m;j++){ if(s[i][j]=='*'){ if(flag==0) num++; x[i][j]=num; flag=1; } else if(s[i][j]=='#') flag=0; } } pn[0]=num; num=0; for(int i=0;i<m;i++) { bool flag=0; for(int j=0;j<n;j++){ if(s[j][i]=='*'){ if(flag==0) num++; y[j][i]=num; flag=1; } else if(s[j][i]=='#') flag=0; } } pn[1]=num; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { int u = x[i][j],v=y[i][j]; if(u&&v) addedge(u,v); } int ans=0; for(int i=1;i<=pn[0];++i) { memset(vis,0,sizeof(vis)); ans+=find(i); } printf("%d\n",ans); } return 0; }
时间: 2024-11-05 04:46:03