• [省选联考 2021 A 卷] 矩阵游戏


    一、题目

    点此看题

    二、解法

    首先发现整个矩阵其实之和最后一行最后一列(我称之为边角)有关,如果确定了他们整个矩阵就确定了。考虑调整法,我们先让边角全为 (0),那么得到的矩阵 (a) 很可能是不合法的,我们考虑调整它。

    调整有一个原则就是保持 (a) 能构造出 (b),调整 (a) 的单个元素是困难的。考虑调整一整行或者一整列,奇数位置加 (x) 偶数位置减 (x),这样调整 (b) 是不会变的,而且因为这样做可以调整出所有的边角可能情况,而边角的状态和整个矩阵的状态一一对应,所以这种调整方法是充分的。具体来说有下面的不等式,(r_i,c_j) 分别表示行和列的调整值:

    [0leq pm r_ipm c_j+a_{i,j}leq 10^6 ]

    解决这个不等式很容易想到差分约束,但是会出现 (xleq -y+c) 之类的不等式,这时候可以拆一个表示负数权值的点出来,然后连成对称图就可以保证某点正点和负点的权值相同,但是要讨论很多情况。

    还有一个更简介的方法是把原图进行二染色,让每种颜色对应一种等式:

    [row egin{matrix}+&-&+&-\-&+&-&+\+&-&+&-\-&+&-&+end{matrix} ]

    [col egin{matrix}-&+&-&+\+&-&+&-\-&+&-&+\+&-&+&-end{matrix} ]

    • (i+j) 为奇数:(0leq r_i-c_j+a_{i,j}leq 10^6)
    • (i+j) 为偶数:(0leq -r_i+c_j+a_{i,j}leq 10^6)

    然后用 ( t spfa) 跑图判负环即可,判负环的好方法:维护到每个点的最短路径长度,如果 (geq) 总点数就一定有负环。

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    const int M = 605;
    #define ll long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int T,n,m,cnt[M],vis[M];ll dis[M],a[M][M],b[M][M];
    struct node
    {
        int v;ll c;
    };vector<node> g[M];
    void link(int u,int v,ll c)
    {
        g[u].push_back({v,c});
    }
    void spfa()
    {
        queue<int> q;
        memset(dis,0x3f,sizeof dis);
        memset(vis,0,sizeof vis);
        memset(cnt,0,sizeof cnt);
        dis[1]=cnt[1]=0;vis[1]=1;q.push(1);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            vis[u]=0;
            for(int i=0;i<g[u].size();i++)
            {
                node x=g[u][i];
                if(dis[x.v]>dis[u]+x.c)
                {
                    dis[x.v]=dis[u]+x.c;
                    cnt[x.v]=cnt[u]+1;
                    if(cnt[x.v]>=n+m) {puts("NO");return ;}
                    if(!vis[x.v]) vis[x.v]=1,q.push(x.v);
                }
            }
        }
        puts("YES");
        for(int i=1;i<=n;i++,puts(""))
            for(int j=1;j<=m;j++)
            {
                ll t=dis[i]-dis[j+n];
                if((i+j)%2)
                    printf("%lld ",t+a[i][j]);
                else
                    printf("%lld ",-t+a[i][j]);
            }
    }
    void work()
    {
        memset(a,0,sizeof a);
        n=read();m=read();
        for(int i=1;i<=n+m;i++)
            g[i].clear();
        for(int i=1;i<n;i++)
            for(int j=1;j<m;j++)
                b[i][j]=read();
        for(int i=n-1;i>=1;i--)
            for(int j=m-1;j>=1;j--)
                a[i][j]=b[i][j]-a[i+1][j]
                -a[i][j+1]-a[i+1][j+1];
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                if((i+j)%2)
                {
                    //0<=ri-cj+aij<=1e6
                    //cj<=ri+aij,ri<=cj+1e6-aij
                    link(i,j+n,a[i][j]);
                    link(j+n,i,1e6-a[i][j]);
                }
                else
                {
                    //0<=-ri+cj+aij<=1e6
                    //ri<=cj+aij,cj<=ri+1e6-aij
                    link(j+n,i,a[i][j]);
                    link(i,j+n,1e6-a[i][j]);
                }
            }
        spfa();
    }
    signed main()
    {
        T=read();
        while(T--) work();
    }
    
    
  • 相关阅读:
    FreeMarker MyEclipse IDE
    Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring
    Mybatis SqlSessionTemplate 源码解析
    Mybatis Interceptor 拦截器原理 源码分析
    MyBatis Mapper 接口如何通过JDK动态代理来包装SqlSession 源码分析
    MyEclipse SVN 下面切换用户的解决方案
    SpringMVC 多个数据源 配置多个事物管理器 Multiple Transaction Managers
    Activiti 获取定义
    [No000066]python各种类型转换-int,str,char,float,ord,hex,oct等
    [No000065]python 获取当前时间
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15026223.html
Copyright © 2020-2023  润新知