2021年儿童节J 智乃酱的配电箱谜题

智乃酱的配电箱谜题

https://ac.nowcoder.com/acm/contest/16489/J

这是一道线性代数经典题,问题来了,为什么儿童节要做线性代数呢。
阿巴阿巴阿巴,我也不知道,可能我就是想出个数学题吧。(线性代数和数奥也差不多不是)

首先肯定可以想到k很小,可以矩阵建图。考虑每一层网络之间的图都建成一个矩阵。

例如第一层网络到第二层网络。如果第i个开关链接下层的第j个接线柱,矩阵的第i行第j列就是1,反之就是0。

例如样例中的上层网络就是

这时候继续看样例,如果数理基础好的话其实立刻就反应过来了,为啥呢,因为样例中下层网络直接连上去的,不起任何作用。

我们要构造答案的中层网络为

然后进一步发现


它们做矩阵乘的结果是单位元e。它会是某种巧合么?当然不可能是什么巧合啊。这个题讲到这里估计有线代基础的同学就已经会了。

ok,现在回到问题本身,对于某一层矩阵,当我们定义矩阵的第i行第j列为第i个接线柱是否控制接下层的第j个接线柱。控制为1,不控制为0时。

考虑两层网络的影响如何合并,即假设现在有两张用矩阵建的图,第一个矩阵A表示第一层中第i行第k列为第i个接线柱是否控制接第二层的第k个接线柱。第二个矩阵B表示第二层中第k行第j列为第k个接线柱是否控制接第三层的第j个接线柱。

现在如果我问,第一层的第i个接线柱是否对第三场第j个接线柱有控制关系,记这个关系为,如何用数学公式表示?

你会发现合并两层控制网络这个操作的代数意义恰好是模二意义下的矩阵乘。

设上层网络为矩阵A,中间层网络为矩阵x,下层网络为矩阵B。

最终达到的效果“第i开关仅控制第i个灯泡”,为矩阵乘法单位元e。

则有方程式

利用逆元移项
也就是说本题只要求上下两层网络矩阵的逆矩阵,再做模二意义下的乘法即可。
最后再遍历邻接矩阵输出中层网络图。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=105;
int A[MAXN][MAXN<<1];
struct mat
{
	int row;
	int col;
	int a[MAXN][MAXN];
	mat(int n=0,int m=0,long long p=0)
	{
		row=n;
		col=m;
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=m;++j)
			{
				a[i][j]=0;
			}
		}
		for(int i=1;i<=n;++i)
		{
			a[i][i]=p;
		}
	}
	void row_minus(int a,int b)
    {
        for(int i=1;i<=2*row;++i)
        {
            A[a][i]^=A[b][i];
        }
        return;
    }
    void row_swap(int a,int b)
    {
        for(int i=1;i<=2*row;++i)
        {
            swap(A[a][i],A[b][i]);
        }
    }
    mat inv()
    {
        memset(A,0,sizeof(A));
        for(int i=1;i<=row;++i)
        {
            for(int j=1;j<=row;++j)
            {
                A[i][j]=a[i][j];
                A[i][row+j]=i==j;
            }
        }
        for(int i=1;i<=row;++i)
        {
            if(!A[i][i])
            {
                for(int j=i+1;j<=row;++j)
                {
                    if(A[j][i])
                    {
                        row_swap(i,j);
                        break;
                    }
                }
            }
            assert(A[i][i]);
            for(int j=i+1;j<=row;++j)
            {
                if(A[j][i])
                {
                    row_minus(j,i);
                }

            }
        }
        for(int i=row;i;--i)
        {
            for(int j=i-1;j;--j)
            {
                if(A[j][i])
                {
                    row_minus(j,i);
                }
            }
        }
        mat ret(row,row);
        for(int i=1;i<=row;++i)
        {
            for(int j=1;j<=row;++j)
            {
                ret.a[i][j]=A[i][row+j];
            }
        }
        return ret;
    }
    int count()
    {
        int ret=0;
        for(int i=1;i<=row;++i)
		{
			for(int j=1;j<=col;++j)
			{
			    ret+=a[i][j];
			}
		}
		return ret;
    }
};
mat operator *(const mat &x,const mat &y)
{
	mat ans;
	for(int i=1;i<=x.row;++i)
	{
		for(int j=1;j<=y.col;++j)
		{
			ans.a[i][j]=0;
			for(int k=1;k<=x.col;++k)
			{
				ans.a[i][j]^=x.a[i][k]&y.a[k][j];
			}
		}
	}
	ans.row=x.row;
	ans.col=y.col;
	return ans;
}
void operator *=(mat &x,mat y)
{
	x=x*y;
}
int n,m,k,u,v;
mat a,b,c;
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    a.row=a.col=b.row=b.col=k;
    for(int i=1;i<=n;++i)
    {
        scanf("%d %d",&u,&v);
        a.a[u][v]=1;
    }
    for(int i=1;i<=m;++i)
    {
        scanf("%d %d",&u,&v);
        b.a[u][v]=1;
    }
    c=a.inv()*b.inv();
    printf("%d\n",c.count());
    for(int i=1;i<=c.row;++i)
    {
        for(int j=1;j<=c.col;++j)
        {
            if(c.a[i][j])
            {
                printf("%d %d\n",i,j);
            }
        }
    }
    return 0;
}


全部评论
如何评价线性基瞎搞骗了40%
1 回复 分享
发布于 2021-06-01 21:17

相关推荐

07-11 22:27
中南大学 Java
程序员牛肉:学历的话没问题。但是没问题的也就只有学历了。 其实你的整体架构是正确的,博客接着干。但是项目有点过于简单了。从后端的角度上讲,你这也就是刚入门的水平,所以肯定约面试够呛。 如果你要应聘后端岗位,那你第一个项目竟然是仿写操作系统。这个你要面试官咋问你。你一定要记住一点,你简历上写的所有的东西,都是为了证明你有能力胜任当前的岗位,而不是为了证明你自己会什么。 如果你只是浅浅的做几个项目,描述也都是烂大街。技术点也都是各种混水类的配置类需求,那你就不要幻想自己能走多远。一定要保持思考,保持学习。
点赞 评论 收藏
分享
DKS233:(1)专业技能:Java8也太旧了,最少也要了解到JDK17吧,可以参考现在SpringBoot支持的Java最低版本,熟悉mysql基本理论具体指啥,是锁这种具体原理还是分库分表这些业务场景,spring这些专业词汇,大小写要写对(全篇简历都有这个问题,显得不严谨),熟悉使用框架进行业务开发就别写了,如果要写,起码要写到框架原理部分吧,比如aop,启动原理什么的,springcloud具体指哪些模块呢,写清楚,网关还是鉴权还是什么,“改造”没必要写吧,你直接说用springcloud开发的不就行了(2)项目经历:首先格式就有大问题,时间怎么能换行呢,调整一下,响应速度那个,如果指的是将部分数据从其他数据库转到redis的提升就别写了,因为这个不算难点,redis可以写写分布式这些,比如容灾怎么实现的,数据库同步怎么做的
点赞 评论 收藏
分享
家里人这种思想对吗?最近找到了某大厂算法岗的实习,家里人一直跟我说要给领导买点东西,搞好关系,我真的搞不清楚他们这种思想到底怎么来的,真的很烦他们教我做事,他们总觉得自己是对的,我不照着他们的想法做,就觉得我态度不对,之前找实习也是只会嘴巴上对我说你要加油,你要努力,但是根本不知道我背后付出了多少努力,真的好烦被教做事的感觉。
青春运维少年不会梦到...:小时候老爸每次外出打工,我都会说注意安全,可是我真的懂老爸的工作吗,一个小学文凭的人出去打工能有什么安全的工作,可是老爸还是慈祥的回应我,仿佛每天能安全回家都归功于我的祈福。到了现在,我跨越3000多公里去了陌生的城市,老爸还是那个老爸,只不过现在多了问我的情况,会问我适应新城市吗,适应工作强度吗,到最后真的好奇,问我这个工作是干啥的;老爸没文化,不知道计算机网络有七层结构,也不知道云saas订阅,我只能说,就像汽车修理厂一样,我是那个修车的师傅。老爸可能觉得真的理解不了我的工作,之后也就没多问了。不过仍然还是给我传授他的经验,对于老爸来说,他也知道我做的是他难以理解的工作,知道小县城的那套江湖规矩难以闯荡大城市,但是他依旧会关心我。。。
实习的内耗时刻
点赞 评论 收藏
分享
评论
5
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务