二分图最小路径覆盖=|v|-最大匹配。此题为有向图,切所有边正反向存了两遍,所以结果匹配数要除以2
// // main.cpp // poj3020 // // Created by Fangpin on 15/5/29. // Copyright (c) 2015年 FangPin. All rights reserved. // #include <iostream> #include <cstdio> #include <vector> #include <cstring> using namespace std; const int MAXN=5000; int link[MAXN],n,m,total,h[50][20]; vector<int> g[MAXN]; char mp[55][22]; bool vis[MAXN]; bool dfs(int x){ for(int i=0;i<g[x].size();++i){ int y=g[x][i]; if(vis[y]) continue; vis[y]=true; if(link[y]==-1 || dfs(link[y])){ link[y]=x; return true; } } return false; } int hungry(){ memset(link,-1,sizeof(link)); int ans=0; for(int i=1;i<=total;++i){ memset(vis,false,sizeof(vis)); if(dfs(i)) ++ans; } return ans; } int main(int argc, const char * argv[]) { // insert code here... // std::cout << "Hello, World!\n"; int t; scanf("%d",&t); char s[10000]; while(t--){ scanf("%d%d",&n,&m); for(int i=0;i<=n*m;++i) g[i].clear(); memset(mp,'o',sizeof(mp)); total=0; for(int i=0;i<n;++i){ scanf("%s",s); int len=strlen(s); for(int j=0;j<len;++j){ mp[i+1][j+1]=s[j]; if(s[j]=='*') h[i+1][j+1]=++total; } } for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j){ if(mp[i][j]=='*'){ int x=h[i][j]; if(mp[i-1][j]=='*') g[x].push_back(h[i-1][j]); if(mp[i+1][j]=='*') g[x].push_back(h[i+1][j]); if(mp[i][j-1]=='*') g[x].push_back(h[i][j-1]); if(mp[i][j+1]=='*') g[x].push_back(h[i][j+1]); } } } cout<<total-hungry()/2<<endl; } return 0; }
时间: 2024-10-14 01:40:07