我反正是絕對做不出來。
我們把每個決策的
怎麼求C?
後兩項爲定值,只需前兩項最大即可。
那麼令二分圖的權值
這一題的複雜度好像並不明確。。。
這裏再說一下KM算法的優化,sla要在外層循環清INF,每次DFS不是相等子圖中的邊則需要更新,然後update記得減去。因爲sla是Y’中的點與X中的點的
#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<cassert>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<sstream>
#include<climits>
#define X first
#define Y second
#define DB double
#define lc now<<1
#define rc now<<1|1
#define MP make_pair
#define LL long long
#define pb push_back
#define sqr(_) ((_)*(_))
#define INF 0x3f3f3f3f
#define pii pair<int,int>
#define pdd pair<DB,DB>
#define ull unsigned LL
#define DEBUG(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
template<typename T>void Read(T& x)
{
x=0;int flag=0,sgn=1;char c;
while(c=getchar())
{
if(c=='-')sgn=-1;
else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;
else if(flag)break;
}
x*=sgn;
}
const int MAXN=80;
int T,n,A[MAXN][MAXN],B[MAXN][MAXN],G[MAXN][MAXN];
struct KM{
bool S[MAXN],T[MAXN];
int lx[MAXN],ly[MAXN],sla[MAXN],left[MAXN];
bool match(int i)
{
S[i]=1;
for(int j=1;j<=n;j++)
if(!T[j])
{
if(lx[i]+ly[j]==G[i][j])
{
T[j]=1;
if(!left[j]||match(left[j])){
left[j]=i;
return 1;
}
}
else
sla[j]=min(sla[j],lx[i]+ly[j]-G[i][j]);
}
return 0;
}
void update()
{
int d=INF;
for(int i=1;i<=n;i++)if(!T[i])
d=min(d,sla[i]);
for(int i=1;i<=n;i++)
{
if(S[i])lx[i]-=d;
if(T[i])ly[i]+=d;
else
sla[i]-=d;
}
}
pii km()
{
pii res=MP(0,0);
memset(left,0,sizeof(left));
memset(ly,0,sizeof(ly));
memset(lx,0,sizeof(lx));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
lx[i]=max(lx[i],G[i][j]);
for(int i=1;i<=n;i++)
{
memset(sla,INF,sizeof(sla));
while(1)
{
memset(S,0,sizeof(S));
memset(T,0,sizeof(T));
if(match(i))break;
else update();
}
}
for(int i=1;i<=n;i++)
{
res.X+=A[left[i]][i];
res.Y+=B[left[i]][i];
}
return res;
}
}Graph;
void init()
{
Read(n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
Read(A[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
Read(B[i][j]);
}
void build(pii& l,pii& r)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
G[i][j]=(r.Y-l.Y)*A[i][j]+(l.X-r.X)*B[i][j];
}
int work(pii l,pii r)
{
build(l,r);
pii mid=Graph.km();
if(l==mid||r==mid)return min(l.X*l.Y,r.X*r.Y);
return min(work(l,mid),work(mid,r));
}
void solve()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
G[i][j]=-A[i][j];
pii st=Graph.km();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
G[i][j]=-B[i][j];
pii ed=Graph.km();
cout<<work(st,ed)<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("frame.in","r",stdin);
freopen("frame.out","w",stdout);
#endif
Read(T);
while(T--)
{
init();
solve();
}
}