[TJOI2015]线性代数 题解
[TJOI2015]线性代数 题解
Problem
为了提高智商,ZJY 开始学习线性代数。
她的小伙伴菠萝给她出了这样一个问题:给定一个\(n \times n\)的矩阵\(B\)和一个\(1 \times n\)的矩阵\(C\)。求出一个\(1 \times n\)的01矩阵\(A\),使得\(D=(A \times B -C) \times A^{T}\)最大,输出\(D\)(\(1 \leq n \leq 500\))。
Solution
正解是网络流......这篇题解只是提供一个乱搞方法。
这题乍一看是线性代数,感觉推式子暴力化表达式会很麻烦,似乎不可做的样子。
但是,发现\(n\)的范围很小,再加之\(A\)是\(1 \times n\)的01矩阵,于是情况便变得简单起来,我们可以尝试随机一个\(A\),再暴力算出\(D\),更新答案,每一次的复杂度是\(O(n^2)\)的,大概能随机将近1000次,正确率还是比较高的。
还有一个要注意的地方,\(A\)矩阵初始化应该是全1,因为要使\(D\)最大,这样概率会大很多,两种初始化方法得分简直天壤之别......
Code
#include<bits/stdc++.h>
#define eps 1e-8
using namespace std;
int n;
struct Matrix{
int C,L;
int M[505][505];
Matrix(){
C=L=0;
memset(M,0,sizeof M);
}
friend Matrix operator - (Matrix A,Matrix B){
Matrix res;
res.C=A.C;res.L=B.L;
for(register int i=1;i<=A.C;++i)
for(register int j=1;j<=B.L;++j)
res.M[i][j]=A.M[i][j]-B.M[i][j];
return res;
}
friend Matrix operator * (Matrix A,Matrix B){
Matrix res;
res.C=A.C;res.L=B.L;
for(register int i=1;i<=A.C;++i)
for(register int k=1;k<=A.L;++k)
for(register int j=1;j<=B.L;++j)
res.M[i][j]+=A.M[i][k]*B.M[k][j];
return res;
}
}A,B,C,Ans;
Matrix Trans(Matrix A){
Matrix res;
res.C=A.L;res.L=A.C;
for(register int i=1;i<=A.C;++i)
for(register int j=1;j<=A.L;++j)
res.M[j][i]=A.M[i][j];
return res;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
void Simulate_Anneal(){
Matrix Res=A;
double T=2000,d=0.998;
while(T>eps&&1.0*clock()/CLOCKS_PER_SEC<0.8){
Matrix Now=Res;
Now.M[1][rand()%n+1]^=1;
Matrix Sum=(Now*B-C)*Trans(Now);
if(Sum.M[1][1]>Ans.M[1][1]){
A=Res=Now;
Ans.M[1][1]=Sum.M[1][1];
}
else if(exp((Sum.M[1][1]-Ans.M[1][1])/T)>1.0*rand()/RAND_MAX)
Res=Now;
T*=d;
}
return;
}
int main(){
n=read();
B.C=n;B.L=n;
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j)
B.M[i][j]=read();
C.C=1;C.L=n;
for(register int i=1;i<=n;++i)
C.M[1][i]=read();
A.C=1;A.L=n;
for(register int i=1;i<=n;++i)
A.M[1][i]=1;
Ans=(A*B-C)*Trans(A);
srand(time(0));
while(1.0*clock()/CLOCKS_PER_SEC<0.8)
Simulate_Anneal();
printf("%d\n",Ans.M[1][1]);
return 0;
}