CF1366C Palindromic Paths(思维+并查集)

题意:

给出一个最大30*30的01矩阵,询问,最少修改几个节点,使得从起点(右上角)到终点(左下角)的所有路径全部为回文串。

题解:

考试的时候时间仓促,思考了正解的前面几步,最后的维护集合出了问题,思维还是要加强,不能C题都出不了。。。

思路就是,两个距离起点和终点距离相同的点必定要一样,也就是同属于一个集合。最后对每个集合统计集合里0的数量和1的数量,取较小值,加起来即可。

关键的一步在于集合的维护,考试的时候强行遍历所有节点,用并查集处理,这样会有O(N*N*M*M)的时间复杂度,最后TLE了。

正解是,不用维护集合的信息,只要维护每个集合01节点的数量即可,那么每个节点所属的集合编号就是min(i+j,n+m+2-i-j),遇到两个坐标相反的节点就忽略,这样处理出每个集合的信息,时间复杂度O(N*M)。

思维还是要练。光会并查集没啥用,要去主动的利用题目的性质优化算法。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
int a[maxn][maxn];
int cnt1[maxn];
int cnt2[maxn];
int t,n,m;
int main () {
    scanf("%d",&t);
    while (t--) {
        scanf("%d%d",&n,&m);
        for (int i=0;i<n+m;i++) cnt1[i]=cnt2[i]=0;
        for (int i=0;i<n;i++)
            for (int j=0;j<m;j++) {
                scanf("%d",&a[i][j]);
                int tt=i+j;
                if (tt==n+m-2-i-j) continue;
                tt=min(tt,n+m-2-i-j);
                cnt1[tt]+=a[i][j];
                cnt2[tt]++;
             }
         int ans=0;
         for (int i=0;i<n+m;i++) ans+=min(cnt1[i],cnt2[i]-cnt1[i]);
         printf("%d
",ans);
    }
}
原文地址:https://www.cnblogs.com/zhanglichen/p/13098774.html