传送门biu~
把每种卡片建一个节点,每位除了小C以外的小朋友建一个节点。如果小C有一种卡片的张数大于1,则连一条从源点到此种卡片的弧,流量为张数减一;如果小C有一种卡片的张数为0,则连一条此种卡片到汇点的弧,流量为1。同理,如果一个小朋友有一种卡片的张数大于1,则连一条这个小朋友到此种卡片的弧,流量为张数减一;如果一个小朋友有一种卡片的张数为0,则连一条此种卡片到这个小朋友的弧,流量为1。显然跑一边网络最大流所得的答案即为小C多获得的卡片的种类数,加上小C已有的种类数即为所求答案。
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
int n,m,ans,S,T;
int card[205][205];
int fir[505],head[505],dep[505],nex[500005],to[500005],cap[500005],tp=1;
inline void add(int x,int y,int c){
nex[++tp]=head[x];
head[x]=tp;
to[tp]=y;
cap[tp]=c;
}
inline int bfs(){
memset(dep,0,sizeof(dep));
dep[S]=1;
queue<int>q;q.push(S);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=nex[i]){
if(!dep[to[i]] && cap[i]){
dep[to[i]]=dep[x]+1;
q.push(to[i]);
}
}
}
return dep[T];
}
int dfs(int x,int now){
if(x==T || !now) return now;
int c=0;
for(int &i=fir[x];i;i=nex[i]){
if(dep[to[i]]==dep[x]+1 && cap[i]){
int f=dfs(to[i],min(cap[i],now));
cap[i]-=f;
cap[i^1]+=f;
c+=f;
now-=f;
}
}
return c;
}
inline int Dinic(){
int c=0;
while(bfs()){
for(int i=1;i<=n+m;++i) fir[i]=head[i];
fir[S]=head[S];fir[T]=head[T];
c+=dfs(S,INF);
}
return c;
}
int main(){
scanf("%d%d",&n,&m);S=n+m+1;T=n+m+2;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
scanf("%d",&card[i][j]);
if(i==1){
if(card[i][j]) ++ans;
}
else{
if(card[i][j]==0) add(j,m+i,1),add(m+i,j,0);
if(card[i][j]>1) add(m+i,j,card[i][j]-1),add(j,m+i,0);
}
}
}
for(int i=1;i<=m;++i){
if(card[1][i]>1) add(S,i,card[1][i]-1),add(i,S,0);
if(!card[1][i]) add(i,T,1),add(T,i,0);
}
printf("%d",ans+Dinic());
return 0;
}