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\n",ans); } }