建图,使源点为文,汇点为理,初始总喜悦度减可获得的最大喜悦度相当于图的最小割。
先从源点向每个人连流量为选文喜悦度的边,且从每个人向汇点连流量为选理喜悦度的边。然后对于没一组相邻的同学都单独建一个点,若是同选文,就从源点向该点连流量为额外喜悦度的边,且从该点向其所代表的两个人连流量为无线的边,选理道理相似。这样保证了只要任意一人不选该科,就不会获得额外喜悦度。然后跑最大流即可。
#include
#include
#include
#include
using namespace std;
const int N=50000,M=300000,inf=0x7fffffff;
namespace io{
const int SIZE=(1<<21)+1;
char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int qr;
#define gc() (iT==iS?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iT==iS?EOF:*iS++):*iS++)
inline void flush(){
fwrite(obuf,1,oS-obuf,stdout);
oS=obuf;
}
inline void putc(char x){
*oS++ =x;
if(oS==oT)flush();
}
template
inline void gi(I &x){
for(c=gc();c<'0'||c>'9';c=gc());
for(x=0;c>='0'&&c<='9';c=gc())x=x*10+(c&15);
}
template
inline void print(I &x){
if(!x)putc('0');
while(x)qu[++qr]=x%10+'0',x/=10;
while(qr)putc(qu[qr--]);
}
}
using io::gi;
using io::putc;
using io::print;
struct edge{
int y,f,next;
}data[M];
int n,m,s,t,num,num1,tot,h[N],dep[N],cur[N];
queue q;
inline void addedge(int x,int y,int f){
data[++num].y=y,data[num].f=f,data[num].next=h[x],h[x]=num;
data[++num].y=x,data[num].f=0,data[num].next=h[y],h[y]=num;
}
inline int min1(int a,int b){
return a0)dep[v]=dep[u]+1,q.push(v);
}
}
return dep[t];
}
int dfs(int u,int t,int lim){
if(u==t)return lim;
int res=0;
for(int &i=cur[u];i!=-1;i=data[i].next){
int v=data[i].y;
if(dep[v]==dep[u]+1&&data[i].f>0){
int fmax=dfs(v,t,min1(lim-res,data[i].f));
if(fmax){data[i].f-=fmax,data[i^1].f+=fmax,res+=fmax;if(res==lim)return res;}
}
}
return res;
}
inline int dinic(){
int ans=0;
while(bfs())ans+=dfs(s,t,inf);
return ans;
}
int main(){
gi(n),gi(m);s=0,t=1,tot=0;
memset(h,-1,sizeof h),num=-1;
for(int y=1,i=1;i<=n;++i)for(int x,j=1;j<=m;++j)gi(x),++y,tot+=x,addedge(s,y,x);
for(int y=1,i=1;i<=n;++i)for(int x,j=1;j<=m;++j)gi(x),++y,tot+=x,addedge(y,t,x);
num1=n*m+1;
for(int i=1;i