ACM-ICPC Nanjing Onsite 2018 I. Magic Potion
题意:类似二分图匹配给的题目,不过这次在这里给出了k,表示没人可以再多一次匹配机会,这次匹配不能用上一次被匹配的对象
分析:不能用匈牙利做俩次匹配,因为俩次的最大匹配并不等价于总和的匹配,事实证明,你用俩次匹配后会被卡在17个样例
既然二分图不能用匈牙利,那么只能考虑用网络流,这里讲到对于k的处理,这里分配的k次得分配完后保证每个英雄至多消灭2个怪兽,所以只要在起点在建一个顶点,连容量为k的边,再在该顶点连线 向英雄容量为1的边
#include<bits/stdc++.h> using namespace std; const int M=1500; const int N=6e5+5; const int inf=0x3f3f3f3f; int tot,s,t,head[M],cur[M],deep[M]; struct node{ int v,w,nextt; }e[N]; void addedge(int u,int v,int w){ e[tot].v=v; e[tot].w=w; e[tot].nextt=head[u]; head[u]=tot++; e[tot].v=u; e[tot].w=0; e[tot].nextt=head[v]; head[v]=tot++; } bool bfs(){ memset(deep,0,sizeof(deep)); queue<int>que; que.push(s); deep[s]=1; while(!que.empty()){ int u=que.front(); que.pop(); for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(e[i].w&&deep[v]==0){ deep[v]=deep[u]+1; if(v==t) return true; que.push(v); } } } return deep[t]!=0; } int dfs(int u,int fl){ if(u==t) return fl; int x=0,ans=0; for(int i=cur[u];~i;i=e[i].nextt){ int v=e[i].v; if(e[i].w>0&&deep[v]==deep[u]+1){ x=dfs(v,min(e[i].w,fl-ans)); e[i].w-=x; e[i^1].w+=x; ans+=x; if(e[i].w) cur[u]=i; if(ans==fl) return ans; } } if(ans==0) deep[u]=0; return ans; } int dinic(){ int ans=0; while(bfs()){ for(int i=0;i<=t;i++) cur[i]=head[i]; ans+=dfs(s,inf); } return ans; } int main(){ int n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i=0;i<=n+m+2;i++) head[i]=-1; for(int i=1;i<=n;i++){ int x; scanf("%d",&x); while(x--){ int y; scanf("%d",&y); addedge(i,y+n,1); } } s=0,t=n+m+2; for(int i=1;i<=n;i++) addedge(s,i,1); addedge(s,n+m+1,k); for(int i=1;i<=n;i++) addedge(n+m+1,i,1); for(int i=1;i<=m;i++) addedge(i+n,t,1); printf("%d\n",dinic()); return 0; }