Description
Solution
按照最小割求最大权闭合子图的思路,我们先这样:
[add(S,id_{wen}) add(id_{li},T)
]
然后我们求最小割的时候割哪个就代表不选哪个(其实不大一样……)
对于同桌和前后桌的情况,我们对含义建图:
新拎出来一个点 (x)
如果是文科相关就 (add(S,x,val)) 同时,从这个点向相邻的两个点建边,权重 (inf)
理科就 (add(x,T,val)) 同时从相关联的点向这个点建边,权重 (inf)
跑一遍最小割即可,拿总的边权和减去最小割
正确性?
为啥每个人只能选一科?
画画图,思考一下连通性就能证完了(或者参考这里的图画画)
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=7e5+10;
struct node{
int to,lim,nxt;
}e[N<<1];
int head[N],cnt=1,dep[N],sum,S,T,n,m,tot;
inline void adde(int u,int v,int w)
{
e[++cnt].lim=w; e[cnt].to=v; e[cnt].nxt=head[u];
return head[u]=cnt,void();
} queue<int> q;
inline void add(int u,int v,int w){return adde(u,v,w),adde(v,u,0);}
inline bool bfs()
{
memset(dep,0,sizeof(dep)); dep[S]=1;
while(q.size()) q.pop(); q.push(S);
while(!q.empty())
{
int fr=q.front(); q.pop();
for(int i=head[fr];i;i=e[i].nxt)
{
int t=e[i].to;
if(!dep[t]&&e[i].lim) dep[t]=dep[fr]+1,q.push(t);
}
} return dep[T];
}
inline int dfs(int now,int in)
{
if(now==T) return in; int out=0;
for(int i=head[now];i&∈i=e[i].nxt)
{
int t=e[i].to;
if(e[i].lim&&dep[t]==dep[now]+1)
{
int res=dfs(t,min(e[i].lim,in));
in-=res; out+=res; e[i].lim-=res; e[i^1].lim+=res;
}
}if(!out) dep[now]=0;
return out;
}
inline int id(int x,int y){return (x-1)*m+y;}
signed main()
{
n=read(); m=read(); tot=n*m+2; S=n*m+1,T=n*m+2;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
int x=read(); sum+=x;
add(S,id(i,j),x);
}
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
int x=read(); sum+=x;
add(id(i,j),T,x);
}
}
for(int i=1;i<n;++i)
{
for(int j=1;j<=m;++j)
{
int x=read(); ++tot;
add(S,tot,x); sum+=x;
add(tot,id(i+1,j),1e18+10);
add(tot,id(i,j),1e18+10);
}
}
for(int i=1;i<n;++i)
{
for(int j=1;j<=m;++j)
{
int x=read(); ++tot;
add(tot,T,x); sum+=x;
add(id(i,j),tot,1e18+10);
add(id(i+1,j),tot,1e18+10);
}
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<m;++j)
{
int x=read(); ++tot;
add(S,tot,x); sum+=x;
add(tot,id(i,j),1e18+10);
add(tot,id(i,j+1),1e18+10);
}
}for(int i=1;i<=n;++i)
{
for(int j=1;j<m;++j)
{
int x=read(); ++tot;
add(tot,T,x); sum+=x;
add(id(i,j),tot,1e18+10);
add(id(i,j+1),tot,1e18+10);
}
}
while(bfs()) sum-=dfs(S,1e18+10);
printf("%lld
",sum);
return 0;
}
}
signed main(){return yspm::main();}
Review
1.网络流中逆向思维比较多,比如这种(max=sum-mincut)
2.最小割题目从含义下手,然后根据含义进行网络图的建立
一般在这里都是割啥啥没有的