Happiness解题思路
类似于上面所说的,我们定义如果和 \(S\) 相连说明我们选择文科,如果和 \(T\) 相连就说明选的是理科。
考虑如何建边,肯定是每一个人都建若干个点吧,如果一个点表示我这个人选了理科,那么他要向文科建边,边权是文科的代价,如果我这个人选了文科,就向理科连边,边权是理科的代价。那么如何处理两个人之间同时学文科和同时学理科的代价呢?
短时间内没有想到,但是之后看完题解就会了,比如说如果我们是对于两个东西都要选文科,那么我们有一个办法,就是把文科点连向一个另外的点,边权为如果他们两个都选文科的代价,然后这个点向那两个点都连上正无穷的边,说明这个是断不掉的,那么这就说明,另外两个点但凡有一个东西连向了 \(T\) 他都必须被割掉。然后跑一遍最小割就可以了。
#include <bits/stdc++.h>
using namespace std;
template <typename T>inline void read(T& t){t=0; register char ch=getchar(); register int fflag=1;while(!('0'<=ch&&ch<='9')) {if(ch=='-') fflag=-1;ch=getchar();}while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;}
template <typename T,typename... Args> inline void read(T& t, Args&... args) {read(t);read(args...);}
const int inf=0x3f3f3f3f;
const int M=9e5,N=5e5+10;
template<typename T>
struct FlowGragh{
int n,s,t,cnt=1;
struct Edge{
int from,to;
T flow;
int nxt;
}e[M];
int head[N],dis[N],cur[N];
void adde(int u,int v,T val,T rval=0){
e[++cnt]={u,v,val,head[u]}; head[u]=cnt;
e[++cnt]={v,u,rval,head[v]}; head[v]=cnt;
}
void intt(int nn,int ss,int tt){
n=nn;s=ss;t=tt;
cnt=1;
memset(head,0,sizeof(head));
}
bool bfs(){
queue<int>Q;
memset(dis,0,sizeof(dis));
Q.push(s); dis[s]=1; cur[s]=head[s];
while(!Q.empty()){
int u=Q.front(); Q.pop();
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(!dis[v]&&e[i].flow){
Q.push(v);
dis[v]=dis[u]+1;
cur[v]=head[v];
}
}
}
return dis[t];
}
T dfs(int u,T flow){
if(u==t) return flow;
T rest=flow;
for(int i=cur[u];i;i=cur[u]=e[i].nxt){
int v=e[i].to;
if(dis[v]==dis[u]+1&&e[i].flow){
int fflow=dfs(v,rest<e[i].flow?rest:e[i].flow);
e[i].flow-=fflow;
rest-=fflow;
e[i^1].flow+=fflow;
if(!rest) break;
}
}
if(rest==flow) dis[u]=-1;
return flow-rest;
}
T dinic(){
T res=0,tot=0;
while(bfs())
while(res=dfs(s,1e8)) tot+=res;
return tot;
}
};
int n,m,s=5e5+1,t=5e5+2;
long long sum=0;
FlowGragh<int>A;
int number(int x,int y){return (x-1)*m+y;}
int main(){
read(n,m);
A.intt(t,s,t);
int pcnt=n*m;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
int val;
read(val);
sum+=val;
A.adde(s,number(i,j),val);
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
int val;
read(val);
sum+=val;
A.adde(number(i,j),t,val);
}
for(int i=1;i<n;++i)
for(int j=1;j<=m;++j){
int val;
read(val);
sum+=val;
++pcnt;
A.adde(s,pcnt,val);
A.adde(pcnt,number(i,j),inf);
A.adde(pcnt,number(i+1,j),inf);
}
for(int i=1;i<n;++i)
for(int j=1;j<=m;++j){
int val;
read(val);
sum+=val;
++pcnt;
A.adde(pcnt,t,val);
A.adde(number(i,j),pcnt,inf);
A.adde(number(i+1,j),pcnt,inf);
}
for(int i=1;i<=n;++i)
for(int j=1;j<m;++j){
int val;
read(val);
sum+=val;
++pcnt;
A.adde(s,pcnt,val);
A.adde(pcnt,number(i,j),inf);
A.adde(pcnt,number(i,j+1),inf);
}
for(int i=1;i<=n;++i)
for(int j=1;j<m;++j){
int val;
read(val);
sum+=val;
++pcnt;
A.adde(pcnt,t,val);
A.adde(number(i,j),pcnt,inf);
A.adde(number(i,j+1),pcnt,inf);
}
cout<<sum-A.dinic()<<endl;
return 0;
}
/*
是谁挥霍的时光啊,是谁苦苦的奢望啊
这不是一个问题,也不需要你的回答
No answer.
*/