处理方法:我们先求出最大匹配A,然后枚举每条边,去掉后求最大匹配B,如果B==A那么说明当前边无关紧要,如果B<A,那么说明当前边为必须边.
两种存边方法: 邻接表、邻接矩阵。
邻接表:
#include <cstdio> #include <cstring> #include <vector> #include <iostream> #include <queue> #include <stdlib.h> using namespace std; int pre[105],visit[105]; vector<int>way[105]; int l,r; //l,r就是被禁止的边. int dfs(int step){ int i,next; for(i=0;i<way[step].size();i++){ next=way[step][i]; if(visit[next] || step==l&&i==r)continue; visit[next]=1; if(pre[next]==-1 || dfs(pre[next])){ pre[next]=step; return 1; } } return 0; } int main() { int i,j,n,v,u,m,ans,k,rec,step,cishu=1; while(cin>>n>>m){ for(i=0;i<105;i++)way[i].clear(); cin>>k; for(i=0;i<k;i++){ cin>>u>>v; way[u].push_back(v); } memset(pre,-1,sizeof(pre)); ans=0;rec=0;l=99999,r=99999; for(i=1;i<=n;i++){ memset(visit,0,sizeof(visit)); if(dfs(i)==1)rec++; } for(i=1;i<=n;i++){ for(int d=0;d<way[i].size();d++){ //枚举每条边. memset(pre,-1,sizeof(pre)); step=0; l=i,r=d; //赋值给全局变量表禁止 for(j=1;j<=n;j++){ memset(visit,0,sizeof(visit)); if( dfs(j)==1)step++; } if(step<rec)ans++; } } printf("Board %d have %d important blanks for %d chessmen.\n",cishu,ans,rec); cishu++; } return 0; }
邻接矩阵:
#include<iostream> const int MAXN=110; using namespace std; int m,n,k; int X[MAXN],Y[MAXN]; int cx[MAXN],cy[MAXN]; int map[MAXN][MAXN]; bool mark[MAXN]; int dfs(int u){ //考虑所以yi顶点v for(int v=1;v<=n;v++){ //u与v邻接且没有被访问过 if(!mark[v]&&map[u][v]){ mark[v]=1; //如果v没有匹配,或者v已经匹配了,但从cy[v]出发可以找到一条增广路 if(cy[v]==-1||dfs(cy[v])){ cy[v]=u;//把u匹配给v cx[u]=v;//把v匹配给u return 1; } } } return 0; } //匈牙利算法 int MaxMatch(){ int res=0; memset(cx,-1,sizeof(cx));//从1匹配开始增广,将cx,cy各元素初始化为-1. memset(cy,-1,sizeof(cy)); for(int i=1;i<=n;i++){ //从每个未盖点出发寻找增广路 if(cx[i]==-1){ memset(mark,false,sizeof(mark)); //每寻找到一条增广路可使匹配数增加1 if(dfs(i)){ res++; } } } return res; } int main(){ int _case=1; while(~scanf("%d%d%d",&n,&m,&k)){ memset(map,0,sizeof(map)); for(int i=1;i<=k;i++){ scanf("%d%d",&X[i],&Y[i]); map[X[i]][Y[i]]=1; } int ans=MaxMatch();//求二分图最大匹配的匈牙利算法 int count=0; for(int i=1;i<=k;i++){ map[X[i]][Y[i]]=0;//试着去掉每一条边 int res=MaxMatch(); map[X[i]][Y[i]]=1;//恢复 if(res<ans)count++;//如果比先前求出的小,说明是重要点 } printf("Board %d have %d important blanks for %d chessmen.\n",_case++,count,ans); } return 0; }