[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;
}
posted @ 2020-09-22 20:49  zjy123456  阅读(173)  评论(0编辑  收藏  举报