测试地址:线性代数
做法:从题目看出题目求的是将A矩阵中元素分为两个集合(取0或取1)使某一个值最大,那么我们可以把这个值转化成某个常数减去某个变量,转成求该变量的最小值,我们注意关键词“分为两个集合”“最小值”,就开始思考这是不是能用最小割解决,实际上是可以的,转化方法见这里。然后写一个最大流算法求出最小割就可以了。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define inf 1000000000
using namespace std;
int n,first[510]={0},tot=1,start=0,end;
int ans=0,sum=0,level[510],s[510]={0};
struct edge {int v,f,next;} e[1000010];
void insert(int a,int b,int f)
{
e[++tot].v=b,e[tot].f=f,e[tot].next=first[a],first[a]=tot;
}
bool makelevel()
{
queue <int> q;
memset(level,-1,sizeof(level));
level[start]=0;
q.push(start);
while(!q.empty())
{
int v=q.front();q.pop();
if (v==end) return 1;
for(int i=first[v];i;i=e[i].next)
if (level[e[i].v]==-1&&e[i].f)
{
level[e[i].v]=level[v]+1;
q.push(e[i].v);
}
}
return 0;
}
int dfs(int v,int maxf)
{
int ret=0,f;
if (v==end) return maxf;
for(int i=first[v];i;i=e[i].next)
if (e[i].f&&level[e[i].v]==level[v]+1)
{
f=dfs(e[i].v,min(maxf-ret,e[i].f));
ret+=f;
e[i].f-=f;
e[i^1].f+=f;
if (ret==maxf) return ret;
}
return ret;
}
int main()
{
scanf("%d",&n);
end=n+1;
for(int i=1;i<=n;i++)
for(int j=1,a;j<=n;j++)
{
scanf("%d",&a);
sum+=a;s[i]+=a;
if (i!=j) insert(i,j,a),insert(j,i,0);
}
for(int i=1,c;i<=n;i++)
{
scanf("%d",&c);
insert(i,end,c),insert(end,i,0);
insert(start,i,s[i]),insert(i,start,0);
}
while(makelevel())
{
ans+=dfs(start,inf);
}
printf("%d",sum-ans);
return 0;
}