GCJ 2009 Round2 A (Crazy Rows)

题意:

给定一个N*N矩阵,每次可以对矩阵进行一次换行操作(只能交换相邻行),求至少多少次操作可以将其转化为上三角矩阵(主对角线上方都是0的矩阵)

 

抽象可得:

定义tail[i] (1<=i<=N, 1<=tail[i]<=N)为a第i行最后一个1所在的位置

通过一定的相邻行交换操作使tail[i]满足 tail[i]  <=  i(条件A)

 

思路:

假设有tail[m]不满足条件A,则此行对于任意tail[i] (i < m)都不满足条件A,为保证受此影响的行恢复正常必须再次交换下来,故为保证操作数最小,只需向下寻找即可。

 

由于对tail[m]的操作需向下交换,故将破坏以下行的条件满足性。为减少讨论次数,从上向下依次讨论。

 

对第n行分析,由上可知从第n行依次向下检查直至tail[m] (n < m) 满足tail[m]<=n,再倒着交换回去即可。

 

子问题:

证明从找到的第一个tail[m1](n<m1)倒着交换回去最佳。

 

证明:

假设tail[m2](n<m2且m1<m2),则将其交换至第n行需m2-n次

而tail[m1]需m1-n次(m1 - n < m2 - n)

另交换m2对导致对第k行(m1<k<m2)造成影响,而此影响的后果较于不受影响的效果是交换次数不变或是增加。


#include <stdio.h>
#include <math.h>
#include <algorithm>

using namespace std;

int tail[50];

int main()
{
	int n;
	while(~scanf("%d", &n))
	{
		// get all items of tail
		for (int i = 1; i <= n; ++i)
		{
			tail[i] = 0;
			int temp;
			for (int j = 1; j <= n; ++j)
			{
				scanf("%d", &temp);
				if(temp==1)
					tail[i] = j;
			}
		}

		int res = 0;
		for (int i = 1; i <= n; ++i)
		{

			int temp_res = 0;
			int j = i;
			while(tail[j] > i)
				j++;

			for (int k = j; k > i; --k)
			{
				swap(tail[k], tail[k-1]);
				res ++;
			}
		}
		printf("%d\n", res);
	}
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值