题意:
给定一个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);
}
}