题目链接:
http://codeforces.com/contest/1139/problem/E
题意:
开始有$n$个同学和$m$,每个同学有一个天赋$p_{i}$和一个俱乐部$c_{i}$,然后在$d$天里,每天早上去除一名同学$k_{i}$,每天中午在每个俱乐部选一个人组成战队。战队的战斗力是最小的不存在的天赋,例如{1,2,3,0}战斗力是4,问每天战队的战斗力最大为多少。
数据范围:
$1 leq m leq n leq 5000$
$0 leq p_i < 5000$
$1 leq c_i leq m$
$1 leq d leq n$
$1 leq k_i leq n$
分析:
每次减边,然后对整体二分图匹配复杂度大概是$Oleft ( n^{3} ight )$
于是想到逆序处理,从后往前处理,逆过程就是加边,由于加边后的ans肯定是递增的,所以复杂度降成$Oleft ( n^{2} ight )$
如果用邻接矩阵复杂度是$Oleft ( n^{3} ight )$用邻接表是$Oleft ( n^{2} ight )$,因为对于二分图这道题的边数为$n$,属于稀疏图,所以用邻接表比较合适
ac代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=5e3+10;; 4 int match[maxn],vis[maxn],ans[maxn],p[maxn],c[maxn],k[maxn],d,n,m; 5 int ma[maxn][maxn],book[maxn],f[maxn],to[maxn],cnt,nex[maxn]; 6 void add(int a,int b) 7 { 8 cnt++; 9 to[cnt]=b; 10 nex[cnt]=f[a]; 11 f[a]=cnt; 12 } 13 bool dfs(int x) 14 { 15 if(vis[x])return false; 16 vis[x]=1; 17 for(int i=f[x]; i; i=nex[i]) 18 { 19 int v=to[i]; 20 if(match[v]==-1||dfs(match[v])) 21 { 22 match[v]=x; 23 return true; 24 } 25 } 26 return false; 27 } 28 int main() 29 { 30 scanf("%d %d",&n,&m); 31 for(int i=0; i<maxn; i++)match[i]=-1; 32 for(int i=1; i<=n; i++) 33 scanf("%d",&p[i]); 34 for(int i=1; i<=n; i++) 35 scanf("%d",&c[i]); 36 scanf("%d",&d); 37 for(int i=1; i<=d; i++) 38 { 39 scanf("%d",&k[i]); 40 book[k[i]]=1; 41 } 42 for(int i=1; i<=n; i++) 43 if(book[i]==0)add(p[i],c[i]); 44 45 for(int i=d; i>=1; i--) 46 { 47 ans[i]=ans[i+1]; 48 while(1) 49 { 50 memset(vis,0,sizeof(vis)); 51 if(dfs(ans[i]))ans[i]++; 52 else break; 53 } 54 int x=k[i]; 55 add(p[x],c[x]); 56 } 57 for(int i=1; i<=d; i++) 58 printf("%d ",ans[i]); 59 return 0; 60 }