网络流做法最要是建边
将m点分割限流
建立一个起点 连接2个点在于n相连 不过一个流量是inf 一个是k
再把n m连起来 跑最大流即可二分图把 n m的边建2遍(注意开的n'是一个新的节点)
跑二分图的时候注意顺序,先跑原本的n的节点 再跑之后新建的n个节点
因为要保证优先不扩流(不用k)
但这样有可能会出现用别的边的流量的情况出现
所以在跑完二分图之后 判断一下原本的n个点可以用的最大流量
在 可用的最大流量+k 与 二分图结果 取min即可
网络流
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
const int maxn=5e6+10;
struct edge{
int u,v,w,next;
}e[maxn*2];
int n,m,k,maxflow,dep[maxn*2],tot=-1,g[maxn*2];
void creatEdge(int u,int v,int w)
{
e[++tot]=(edge){u,v,w,g[u]};
g[u]=tot;
}
int bfs(int s,int t)
{
queue<int>q;
mem(dep,-1);
dep[s]=0;
q.push(s);
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=g[now];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(dep[v]==-1&&e[i].w)
{
dep[v]=dep[now]+1;
q.push(v);
}
}
}
return dep[t]==-1?0:1;
}
int dfs(int s,int t,int lim)
{
if(!lim||s==t) return lim;
int flow=0,f;
for(int i=g[s];i!=-1;i=e[i].next)
{
int v=e[i].v,w=e[i].w;
if(dep[v]==dep[s]+1&&(f=dfs(v,t,min(lim,w))))
{
flow+=f;
lim-=f;
e[i].w-=f;
e[i^1].w+=f;
if(!lim) break;
}
}
return flow;
}
void Dinic(int s,int t)
{
int tot=0;
while(bfs(s,t))
maxflow+=dfs(s,t,inf);
}
int main()
{
int s,t;
mem(g,-1);
cin>>n>>m>>k;
int tp=n+m;
for(int i=1;i<=n;i++)
{
int tt;
cin>>tt;
for(int j=1;j<=tt;j++)
{
int v;
cin>>v;
creatEdge(2*m+i,v,1);
creatEdge(v,2*m+i,0);
}
}
int pos=4*500+1;
for(int i=1;i<=m;i++)
{
creatEdge(i,i+m,1);
creatEdge(i+m,i,0);
creatEdge(i+m,pos+1,1);
creatEdge(pos+1,i+m,0);
}
for(int i=1;i<=n;i++)
{
creatEdge(pos+2,2*m+i,1);
creatEdge(2*m+i,pos+2,0);
creatEdge(pos+3,2*m+i,1);
creatEdge(2*m+i,pos+3,0);
}
creatEdge(pos+4,pos+3,500);
creatEdge(pos+3,pos+4,0);
creatEdge(pos+4,pos+2,k);
creatEdge(pos+2,pos+4,0);
s=pos+4,t=pos+1;
Dinic(s,t);
// cout<<s<<" "<<t<<endl;
cout<<maxflow<<endl;
return 0;
}
二分图
#include<bits/stdc++.h>
using namespace std;
const int maxn=6e5+10;
struct node{
int u,v,next;
}e[maxn];
int n,m,k,temp;
int g[maxn],vis[maxn],xM[maxn],yM[maxn],tot=0;
int chk[maxn];
void make(int u,int v)
{
e[++tot]={u,v,g[u]};
g[u]=tot;
}
int searchpath(int u)
{
for(int i=g[u];i;i=e[i].next)
{
int v=e[i].v;
if(!chk[v])
{
chk[v]=1;
if(yM[v]==-1||searchpath(yM[v]))
{
yM[v]=u;
xM[u]=v;
return 1;
}
}
}
return 0;
}
int Maxmatch()
{
int u,ret=0;
memset(xM,-1,sizeof(xM));
memset(yM,-1,sizeof(yM));
for(u=m+1;u<=temp;u++)
{
if(xM[u]==-1)
{
memset(chk,0,sizeof(chk));
if(searchpath(u)) ret++;
}
}
return ret;
}
int main(){
cin>>n>>m>>k;
temp=m;
for(int i=1;i<=n;i++)
{
int t;
cin>>t;
temp++;
for(int j=1;j<=t;j++)
{
int now;
cin>>now;
make(temp,now);
make(temp+n,now);
}
}
temp+=n;
int ans=Maxmatch();
int tt=0;
for(int u=m+1;u<=m+n;u++)
if(xM[u]!=-1) tt++;
cout<<min(ans,tt+k)<<endl;
return 0;
}