http://acm.hdu.edu.cn/showproblem.php?pid=1281
题意:小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的互相攻击。
所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么?
题解:二分图最大匹配。跑最大流.要使每行每列最多一个车。熟悉二分匹配的人肯定就会想到:把x,y分别当作二分图的两一个部分,最大匹配就是要求的最多的车的数量。这样的原因也很好理解。最大匹配中,每个x点,y点最多只有一条边链接(不包含链接源点和汇点),也就是说,去相同的x或者y,最多只有一个点。要问哪些车是不能没有的,只需要枚举每一个车,如果去掉这个车,最大匹配减小,就是所求的重要点。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> using namespace std; #define inf (1<<29) const int maxn = 1000 , maxm = 100000; int NV,n,m,k; int gap[maxn],dis[maxn],pre[maxn],cur[maxn]; struct Edge { int v,f,next; Edge() {} Edge( int _v,int _f,int _next ) : v(_v),f(_f),next(_next){} }edge[maxm]; int E,head[maxn]; void init() { E=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int f) { edge[E]=Edge(v,f,head[u]); head[u]=E++; edge[E]=Edge(u,0,head[v]); head[v]=E++; } int sap(int st , int en) { int maxf = 0; for(int i=0;i<NV;i++) { dis[i] = gap[i] = 0; cur[i] = head[i]; } int u = pre[st] = st; int aug = inf; gap[0] = NV; while(dis[st] < NV) { loop: for(int &i=cur[u];i!=-1;i=edge[i].next) { int v = edge[i].v; if(edge[i].f && dis[u]==dis[v]+1) { aug = aug < edge[i].f?aug:edge[i].f; pre[v] = u; u = v; if(v == en) { maxf += aug; for(u=pre[u];v!=st;v=u,u=pre[u]) { edge[cur[u]].f -= aug; edge[cur[u]^1].f += aug; } aug = inf; } goto loop; } } int mindis = NV; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(edge[i].f && mindis > dis[v]) { cur[u] = i; mindis = dis[v]; } } if( --gap[dis[u]] == 0 ) break; gap[ dis[u] = mindis + 1 ] ++; u = pre[u]; } return maxf; } pair<int,int> kp[10005]; void Build_Graph( int id ) { int st = 0; int en = n + m + 1; init(); for( int i = 1 ; i <= n ; i++ ) addedge(st,i,1); for( int j = 1 ; j <= m ; j++ ) addedge(j+n,en,1); for( int i = 0 ; i < k ; i++ ) { if( i == id ) continue; addedge(kp[i].first,kp[i].second+n,1); } } int main() { int cas = 0; while( scanf("%d%d%d",&n,&m,&k) != EOF ) { int st = 0; int en = n + m + 1; NV = n+m+2; init(); int a,b; for( int i = 0 ; i < k ; i++ ) { scanf("%d%d",&kp[i].first,&kp[i].second); addedge(kp[i].first,kp[i].second+n,1); } for( int i = 1 ; i <= n ; i++ ) addedge(st,i,1); for( int j = 1 ; j <= m ; j++ ) addedge(j+n,en,1); int maxflow = sap(st,en); int cnt = 0; for( int i = 0 ; i < k ; i++ ) { Build_Graph(i); int cmp = sap(st,en); if( cmp != maxflow ) cnt++; } printf("Board %d have %d important blanks for %d chessmen.\n",++cas,cnt,maxflow); } return 0; }