Description
给出一个NN的矩阵B和一个1N的矩阵C。求出一个1*N的01矩阵A.使得
D=(A*B-C)*AT最大。其中AT为A的转置。输出D
Input
第一行输入一个整数N,接下来N行输入B矩阵,第i行第J个数字代表Bij.
接下来一行输入N个整数,代表矩阵C。矩阵B和矩阵C中每个数字都是不超过1000的非负整数。
Output
输出最大的D
Sample Input
3
1 2 1
3 1 0
1 2 3
2 3 7
Sample Output
2
HINT
1<=N<=500
题解
我怎么连这种题都秒不了啊好垃圾…
式子出来大概是这样
a [ i ] ∗ a [ j ] ∗ B [ i ] [ j ] − a [ i ] ∗ C [ i ] a[i]*a[j]*B[i][j]-a[i]*C[i] a[i]∗a[j]∗B[i][j]−a[i]∗C[i]
是一个模型
有 n 2 n^2 n2个物品 每个物品有价值 选第(i,j)个物品要花费C[i]+C[j]的钱 求最大价值
st->每个B[i][j]连边 边权B[i][j]表示这个物品如果用了有B[i][j]的价值
每个B[i][j]->i和j连边 边权INF 表示这条边不能割掉
每个i->ed连边 边权C[i] 表示如果叉掉这条边的话就可以对B[i][j]做贡献
最小割即可
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
#define zero 5000005
#define inf (1LL<<63-1)
using namespace std;
struct node{int x,y,next;LL c;}a[5110000];int len,last[505*505+5];
void ins(int x,int y,LL c)
{
len++;
a[len].x=x;a[len].y=y;a[len].c=c;
a[len].next=last[x];last[x]=len;
len++;
a[len].x=y;a[len].y=x;a[len].c=0;
a[len].next=last[y];last[y]=len;
}
queue<int> li;
int st,ed;
int h[505*505+5];
bool bt_h()
{
memset(h,0,sizeof(h));h[st]=1;
li.push(st);
while(!li.empty())
{
int x=li.front();
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(!h[y]&&a[k].c)h[y]=h[x]+1,li.push(y);
}
li.pop();
}
return h[ed]>0;
}
LL findflow(int x,LL f)
{
if(x==ed)return f;
LL s=0,t;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(h[y]==h[x]+1&&a[k].c&&s<f)
{
s+=(t=findflow(y,min(a[k].c,f-s)));
a[k].c-=t;a[k^1].c+=t;
}
}
if(!s)h[x]=0;
return s;
}
int n,B[505][505],C[505];
int pt(int x,int y){return x*n+y;}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&B[i][j]);
for(int i=1;i<=n;i++)scanf("%d",&C[i]);
LL sum=0;len=1;
st=n*(n+1)+1;ed=st+1;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
{
ins(st,pt(i,j),B[i][j]);sum+=B[i][j];
ins(pt(i,j),i,inf);ins(pt(i,j),j,inf);
}
for(int i=1;i<=n;i++)ins(i,ed,C[i]);
while(bt_h())sum-=findflow(st,inf);
printf("%lld\n",sum);
return 0;
}