水水水水水

题目大意:

给定一个n*m的图,方格中的数仅由1和0组成,要求从(1,1)到(n,m)的所有路径都成回文串需要修改的最小数量

思路:

我们先画一个图之后,我们会发现路径要成为字符串,则在斜线上相同,如图:

49e43815388242c2ac7876aab60d64b4.jpeg

但是我们在直接遍历斜线的话,会不是很好想,但是也是能写出来的,根据行数和列数的大小分类讨论,总共要遍历个数是(n+m-3)/2,如果(n+m-3)是奇数的话,最中间的那一列我们不用统计,因为(n+m-3)为奇数的话(n+m-1)也是奇数,中间的那一个对应的回文串也就是自己。

代码1:

const int N = 2e5 + 10, M = 5e2 + 10;
int n,m,o;
int a[M][M]; 
void df()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		cin>>a[i][j];
	}
	int ans=0,t1=0,t2=0,op=(n+m-3)/2; 
	if(n<=m)
	{
		for(int i=1;i<=op;i++)
		{
			int x,y;
			x=1;y=i+1;//当前的点
			t1=t2=0;
			while(y>=1&&x<=n)
			{
				if(a[x][y]==1)t1++;
				else t2++;
				x+=1;y-=1;
			}
			x=n;y=m-i;
			while(y<=m&&x>=1)
			{
				if(a[x][y]==1)t1++;
				else t2++;
				x-=1;y+=1;
			}
			ans+=min(t1,t2);
		}
	}
	else
	{
		for(int i=1;i<=op;i++)
		{
			int x,y;
			x=i+1;y=1;
			t1=t2=0;
			while(x>=1&&y<=m)
			{
				if(a[x][y]==1)t1++;
				else t2++;
				x-=1;
				y+=1;
			}
			x=n-i;y=m;
			while(x<=n&&y>=1)
			{
				if(a[x][y]==1)t1++;
				else t2++;
				x+=1;
				y-=1;
			}
			ans+=min(t1,t2);
		} 
	}
	if(a[1][1]!=a[n][m])ans++;
	cout<<ans<<endl;
}

但是还有一种更简单的方法就是我们统计(i+j-1)这一条斜线上的0和1的个数,之后我们再从两边统计即可。

代码2:

const int N = 2e5 + 10, M = 5e2 + 10;
int n,m,o;
int a[M][M],cnt[M][5]; 
void df()
{
	cin>>n>>m;
	memset(cnt,0,sizeof(cnt));
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>a[i][j];
			cnt[i+j-1][a[i][j]]++;
		}
	}
	int ans=0;
	int l=1,r=n+m-1;
	while(l<r)
	{
		ans+=min(cnt[l][0]+cnt[r][0],cnt[l][1]+cnt[r][1]);
		l+=1;
		r-=1;
	}
	cout<<ans<<endl;
}

 

 

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值