題意:
給定一個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);
}
}