题目链接:http://acm.fzu.edu.cn/problem.php?pid=2166
题目大意:给你一列数,问你交换其中两个数的位置后,得到的最小逆序数,如果逆序数不会减小,则输出原来的逆序数。
解题思路:现在给你一列数,a b C d e f G h i j k l m n,假如我们现在交换c和g的位置,那么逆序数的变化量会怎麽样呢?
首先把c和g交换位置,影响的仅仅就是c和g这一段内的逆序数和总逆序数,c和g交换位置,就想当于把c放在g后面,此时序列相当于变为a b d e f G C h i J k l m n;
逆序数变化量就是d到G这一比C大的数和比C小的数的差值,这个比较好理解。
再说从后向前,由于此时cnt里面存的变化量是C移到后面的变化量,那么把G移到前面的变化量也这样求得,不过需要注意的是,在第一个过程求完之后,把G向前面比较的时候不需要再比较C和G的大小,因为在第一个过程已经比较过了,因此如果比较到j位,则相当于是j-1到i的变化量。
代码如下:
#include<stdio.h>
int s[1005],cnt[1005][1005];
int main()
{
int n,i,j;
while(~scanf("%d",&n))
{
int inv=0;//初始逆序数
for(i=1;i<=n;i++)
scanf("%d",&s[i]);
for(i=1; i<n; i++)
{
int t=0;
for(j=i+1; j<=n; j++)
{
if(s[i]>s[j]) t--,inv++;//inv用来记录总逆序数
else if(s[i]<s[j]) t++;
cnt[i][j]=t;//cnt[i][j]表示把第i个数插到第j+1的位置,逆序数变化量
}
}
for(i=n;i>1;i--)
{
int t=0;
for(j=i-1;j>1;j--)
{
if(s[i]>s[j]) t++;
else if(s[i]<s[j]) t--;
cnt[j-1][i]+=t;//从后向前把第i个数插入到第j个位置,变化量
}
}
int min=0;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
if(min>cnt[i][j])
min=cnt[i][j];
printf("%d\n",min+inv);
}
}