原题地址:
思路:该题主要的难度在于建图,统计出该图有多少个 ‘#’,并编号从1到n,建二分图,左边n个点,右边n个点,如果两点之间可以被一个矩形圈住就连边。
则该题就转化为最大匹配问题。 我分别用了匈牙利算法和Hopcroft-Karp算法解该题。算法具体详解见:点击打开链接是
在该题上时间效率上并没有什么差别,如果数据较大的情况下还是Hopcroft-Karp算法比较快,在另一题上有所体现:点击打开链接
1.匈牙利算法 时间复杂度为O(n*m)
#include<stdio.h> #include<math.h> #include<vector> #include<string.h> using namespace std; char str[610][610]; struct Oil { int x; int y; }oil[360010]; bool used[360010]; int count; // #的个数 vector<int>map[360010]; int match[360010]; int k=0; bool judge(Oil o1,Oil o2) { if(o1.x==o2.x &&abs(o1.y-o2.y)==1 ||o1.y==o2.y &&abs(o1.x-o2.x)==1) return true; return false; } bool find(int u) { int i; for(i=0;i<map[u].size();i++) { int v=map[u][i]; if(used[v]) continue; used[v]=true; if(match[v]==-1||find(match[v])) { match[v]=u; return true; } } return false; } int max_match() { int i,res=0; memset(match,-1,sizeof(match)); for(i=0;i<count;i++) { memset(used,false,sizeof(used)); if(find(i)) res++; } return res; } int main() { int t,n,i,j; scanf("%d",&t); while(t--) { count=0; scanf("%d",&n); getchar(); for(i=0;i<n;i++) gets(str[i]); for(i=0;i<n;i++) for(j=0;j<n;j++) { if(str[i][j]=='#') { oil[count].x=i; oil[count++].y=j; } } for(i=0;i<count;i++) map[i].clear(); for(i=0;i<count;i++) for(j=i+1;j<count;j++) { if(judge(oil[i],oil[j])) { map[i].push_back(j); map[j].push_back(i); } } int res=max_match(); printf("Case %d: %d\n",++k,res/2); } return 0; } 2 Hopcroft-Karp,算法O(sqrt(n)*m) f
#include<stdio.h> #include<math.h> #include<vector> #include<queue> #include<string.h> #define INF 1<<31-1 using namespace std; char str[610][610]; struct Oil { int x; int y; }oil[360010]; int count; // #的个数 vector<int>edge[360010]; bool used[360010]; int fx[360010]; int fy[360010]; int dx[360010]; int dy[360010]; int len; bool searchPath() //找寻最短的增广路径 { int i; queue<int>Q; len=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(i=0;i<count;i++) { if(fx[i]==-1) { Q.push(i); dx[i]=0; } } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>len) break; for(i=0;i<edge[u].size();i++) { int v=edge[u][i]; if(dy[v]==-1) { dy[v]=dx[u]+1; if(fy[v]==-1) len=dy[v]; else { dx[fy[v]]=dy[v]+1; Q.push(fy[v]); } } } } if(len!=INF) return true; return false; } bool find(int u) { int i; for(i=0;i<edge[u].size();i++) { int v=edge[u][i]; if(!used[v]&&dy[v]==dx[u]+1) { used[v]=true; if(fy[v]!=-1&&dy[v]==len) continue; if(fy[v]==-1||find(fy[v])) { fy[v]=u; fx[u]=v; return true; } } } return false; } int solve() { int i,res=0; memset(fy,-1,sizeof(fy)); memset(fx,-1,sizeof(fx)); while(searchPath()) { memset(used,0,sizeof(used)); for(i=0;i<count;i++) { if(fx[i]==-1&&find(i)) res++; } } return res; } int k=0; bool judge(Oil o1,Oil o2) { if(o1.x==o2.x &&abs(o1.y-o2.y)==1 ||o1.y==o2.y &&abs(o1.x-o2.x)==1) return true; return false; } int main() { int t,n,i,j; scanf("%d",&t); while(t--) { count=0; scanf("%d",&n); getchar(); for(i=0;i<n;i++) gets(str[i]); for(i=0;i<n;i++) for(j=0;j<n;j++) { if(str[i][j]=='#') { oil[count].x=i; oil[count++].y=j; } } for(i=0;i<count;i++) edge[i].clear(); for(i=0;i<count;i++) for(j=i+1;j<count;j++) { if(judge(oil[i],oil[j])) { edge[i].push_back(j); edge[j].push_back(i); } } int res=solve(); printf("Case %d: %d\n",++k,res/2); } return 0; }