求最大满意值即求最小舍弃满意度,转化为最小割问题。
假设S集为文科,T集为理科。
从s向每个点i连一条流量为art[i]的边(割掉这条边后i点属于T集合,即选择理科,舍弃文科满意度)
从每个点i向t连一条流量为sci[i]的边(同理)
加点i+n表示对于i及与i相邻点是否都选择文科的决策,i+2*n理科
从s向每个i+n连一条流量为sameart[i]的边,从每个i+n向i和i相邻点连一条流量为inf的边
(看图中下方的图:显然如果存在任意一条sci没有割掉,sameart就要割掉,即这几个人中如果存在任意一人选择理科,就不能满足几个人同时选文科的条件,舍弃sameart)
从每个i+2*n向t连一条流量为samesci[i]的边,从每个i和i相邻点向每个i+2*n连一条流量为inf的边(同理)
#include<cstdio>
int num=1,head[40005],ans,x,t,d[40005],h[40005],n,m;
struct node{int to,next,flow;}e[400005];
void add(int u,int v,int flow)
{
e[++num]=(node){v,head[u],flow},head[u]=num;
e[++num]=(node){u,head[v],0},head[v]=num;
}
int min(int a,int b){return a<b?a:b;}
bool bfs()
{
for(int i=0;i<t;i++)d[i]=0;d[t]=1;
int l=0,r=1;h[1]=t;
while(l!=r)
{
int u=h[++l];
for(int i=head[u];i;i=e[i].next)
if(e[i^1].flow)
{
int v=e[i].to;
if(!d[v])d[v]=d[u]+1,h[++r]=v;
}
}
return d[0];
}
int dfs(int u,int flow)
{
if(u==t)return flow;
int ans=0;bool used=0;
for(int i=head[u];i;i=e[i].next)
if(e[i].flow)
{
int v=e[i].to;if(d[u]!=d[v]+1)continue;
int tmp=dfs(v,min(flow,e[i].flow));
if(tmp)
{
flow-=tmp;e[i].flow-=tmp;
ans+=tmp;e[i^1].flow+=tmp;used=1;
if(!flow)break;
}
}
if(!used)d[u]=-1e9;
return ans;
}
int main()
{
scanf("%d%d",&n,&m);t=(n*m)*3+1;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
scanf("%d",&x),ans+=x,add(0,i*m+j-m,x);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
scanf("%d",&x),ans+=x,add(i*m+j-m,t,x);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
{
scanf("%d",&x);ans+=x;int id=i*m+j-m;
add(0,id+n*m,x),add(id+n*m,id,1e9);
if(i>1)add(id+n*m,id-m,1e9);
if(i<n)add(id+n*m,id+m,1e9);
if(j>1)add(id+n*m,id-1,1e9);
if(j<m)add(id+n*m,id+1,1e9);
}
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
{
scanf("%d",&x);ans+=x;int id=i*m+j-m;
add(id+n*m*2,t,x),add(id,id+n*m*2,1e9);
if(i>1)add(id-m,id+n*m*2,1e9);
if(i<n)add(id+m,id+n*m*2,1e9);
if(j>1)add(id-1,id+n*m*2,1e9);
if(j<m)add(id+1,id+n*m*2,1e9);
}
while(bfs()){int tmp=dfs(0,1e9);if(!tmp)break;ans-=tmp;}
printf("%d\n",ans);
}
一点感想:
一定要弄清楚现在求的到底是什么,是【最小舍弃满意值】而不是【最大满意值】,我们已经装满东西了只要负责扔而不要再去想着怎么装。
像这种同时满足条件的【与】问题,尝试转化成最小割用【或】求解,即把要同时满足的条件代表的点汇集到一个加点上,然后连出一条不满足条件要舍弃的值。