这题像上下界网络流一样,把一条边拆成三条,其中原图中的边权值不变,连向超级源点和汇点的边权值改为0就可以。然后把边合并一下。答案为每条边最小容量*权值+建完图后最小费用流。
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 405
#define LL long long
using namespace std;
int v[1005];
LL ans=0;
int ss,S,T,inf=1e9;
struct E{
int to,nxt,cap,d;
}b[100005];
int fst[maxn],cur[maxn],tot=1;
void insert(int f,int t,int c,int d)
{
b[++tot]=(E){t,fst[f],c,d};fst[f]=tot;
b[++tot]=(E){f,fst[t],0,-d};fst[t]=tot;
}
struct flow{
queue<int> Q;
int dis[maxn],inq[maxn];
int fro[maxn],froe[maxn];
bool spfa()
{
for(int i=0;i<=T;i++)
dis[i]=inf;
dis[S]=0; Q.push(S);
while(!Q.empty())
{
int u=Q.front();Q.pop();inq[u]=0;
for(int i=fst[u];i;i=b[i].nxt)
{
if(!b[i].cap) continue;
int v=b[i].to;
if(dis[v]>dis[u]+b[i].d)
{
dis[v]=dis[u]+b[i].d;
fro[v]=u;froe[v]=i;
if(!inq[v]) Q.push(v),inq[v]=1;
}
}
}
return dis[T]!=inf;
}
int maxflow()
{
int ans=0;
while(spfa())
{
int c=0,mn=inf;
for(int i=T;i!=S;i=fro[i])
mn=min(mn,b[froe[i]].cap);
for(int i=T;i!=S;i=fro[i])
{
int x=froe[i];
b[x].cap-=mn;
b[x^1].cap+=mn;
ans+=mn*b[x].d;
}
}
return ans;
}
}Spfa;
int main()
{
int n,m;
scanf("%d%d",&n,&m);
ss=n*2+1;T=ss+1;
insert(S,ss,m,0);
for(int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
insert(i,T,v[i],0);
insert(S,i+n,v[i],0);
insert(ss,i,m,0);
}
int x;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
scanf("%d",&x);
if(x>=0)insert(i+n,j,m,x);
}
printf("%d",Spfa.maxflow());
return 0;
}