开始你不敢敲估计是怕暴力超时,其实不会的我直接暴力,只用了0ms。我也是醉了。
首先x,y轴的二分匹配,然后把跑出的最大匹配中的边删掉,再跑一遍二分匹配,如果这个结果和原来的不一样说明此点就是题目所说的重要点,然后再把删完的这条边再补回去,然后枚举每一个最大匹配的边。
不要惊讶,就这么简单。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int N=100+5; int map[N][N],x[N*N],y[N*N],vis[N],link[N],link1[N]; int n,m,k; bool dfs(int x) { for(int i=1;i<=m;i++) { if(!vis[i]&&map[x][i]) { vis[i]=1; if(link[i]==-1||dfs(link[i])) { link[i]=x; return true; } } } return false; } bool dfs1(int x) { for(int i=1;i<=m;i++) { if(!vis[i]&&map[x][i]) { vis[i]=1; if(link1[i]==-1||dfs(link1[i])) { link1[i]=x; return true; } } } return false; } int main() { int t=1; while(~scanf("%d%d%d",&n,&m,&k)) { for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { map[i][j]=0; } } memset(x,0,sizeof(x)); memset(link,-1,sizeof(link)); for(int i=1;i<=k;i++) { scanf("%d%d",&x[i],&y[i]); map[x[i]][y[i]]=1; } int res=0; for(int i=1;i<=n;i++)//第一遍二分匹配跑出最大匹配 { if(!x[i]) continue; memset(vis,0,sizeof(vis)); if(dfs(i)) { res++; } } int ans=0; for(int i=1;i<=m;i++)//第二遍枚举最大二分匹配里面的边 { int txt=0; if(link[i]!=-1) { map[link[i]][i]=0;//删除 memset(link1,-1,sizeof(link1)); for(int j=1;j<=n;j++) { if(!x[j]) continue; memset(vis,0,sizeof(vis)); if(dfs1(j)) { txt++; } } if(txt!=res) ans++; map[link[i]][i]=1;//切记一定要还原 } } printf("Board %d have %d important blanks for %d chessmen.\n",t++,ans,res); } return 0; }