先献上自己整理的模板:

dinic算法板子:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define ll long long
const int N=2e3+50;
const ll inf=0x3f3f3f3f3f3f3f3f;
struct node{
int v;ll w;
int ne;
}e[N*N];
int n,cnt=0;
ll m;
int head[N];

ll num[N],sum;

int dep[N],a[N][20];

void add(int u,int v,int f)
{
e[cnt]={v,f,head[u]};
head[u]=cnt++;
e[cnt]={u,0,head[v]};
head[v]=cnt++;
}

bool bfs(int s,int ed)
{
memset(dep,-1,sizeof(dep));
dep[s]=1;
queue<int>que;que.push(s);
while(que.size()){
int u=que.front();que.pop();
if(u==ed) break;
for(int i=head[u];i!=-1;i=e[i].ne){
int v=e[i].v;
if(dep[v]!=-1||e[i].w==0) continue;
dep[v]=dep[u]+1;
que.push(v);

}
}
return dep[ed]!=-1;
}

ll dfs(int u,int ed,ll flow)
{
ll res=flow;
if(u==ed) return flow;
for(int i=head[u];i!=-1;i=e[i].ne){
int v=e[i].v;
if(dep[v]!=dep[u]+1||!e[i].w) continue;
ll d=dfs(v,ed,min(res,e[i].w));
e[i].w-=d;///步骤4增广路中所有减去d,
e[i^1].w+=d;///反向边加上d
res-=d;
if(res==0) break;
}
if(flow==res) dep[u]=-1;///这句话可能是流不下去了
return flow-res;///真正有用的流
}
ll dinic(int st,int ed)
{
ll ans=0;
ll d;
while(bfs(st,ed)){///第二步构造残留图
while(d=dfs(st,ed,inf))///第三步找到一条增广路,
ans+=d;///只需要一次dfs过程实现多次增广路
}
return ans;
}

int valid(ll mid)
{

if(mid*m<sum) return 0;
int v;
memset(head,-1,sizeof(head));
cnt=0,v=0;
int s=++v,t=++v;
rep(i,1,7) add(s,++v,1ll*(mid/7+(mid%7>=i))*m);
rep(i,1,n)
{
++v;add(v,t,num[i]);
for(int j=1;j<=7;++j) if(a[i][j]) add(j+2,v,inf);
}
//puts("****");
//printf("s:%d t:%d\n",s,t);
ll res=dinic(s,t);
return res==sum;
}



int main()
{
scanf("%d%lld",&n,&m);
for(int i=1;i<=n;++i){
scanf("%lld",&num[i]);sum+=num[i];
int t;scanf("%d",&t);
while(t--){
int x;scanf("%d",&x);a[i][x]=1;
}
}


ll l=0,r=1e9/m,ans;
while(l<=r){
ll mid=l+r>>1;
if(valid(mid)) r=mid-1,ans=mid;
else l=mid+1;
}
printf("%lld\n",ans);
return 0;
}

定理:一个图的最小割等价于这个图的最大流

最小割:去掉尽量少的边权,使得图不连通

有的题可能会问你 给你一张图去掉最少的边干嘛干嘛的。。

初步了解了dinic算法和其核心思想,但是代码还是需要模板,短时间内可当黑盒子算法用,以后再慢慢考虑脱板打代码。