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);
	}
}


 

發佈了30 篇原創文章 · 獲贊 0 · 訪問量 9157
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章