您的位置:首页 > 其它

[BOI2007]名次排序问题(sorting)

2017-06-09 10:30 281 查看

题目描述

已知参赛选手的得分,你的任务是按照得分从高到底给出选手的排名。遗憾的是,保存选手信息的数据结构只支持一种操作,即将一个选手从位置i移动到位置j,该移动不改变其他选手的相对位置,即如果i > j,位置j和位置i-1之间的选手的位置都比原来加1,相反如果 i < j,则位置i+1和位置j之间的选手的位置都比原来减一。上述移动的操作的代价定义为i+j,这里,位置编号从1开始。请你编程确定一个移动选手的步骤,将选手按照得分从高到低排序,并使整个移动过程的总代价最小。

输入

文件sorting.in第一行为一个整数n(2<=n<=1000),表示选手的人数;接下来的n行,每行一个非负整数Si( 0<=Si<=1000000),表示一个选手的得分。你可以认为每人的得分是不同的。

输出

文件sorting.out的第一行为一个整数,表示移动的次数,接下来的每一行表示一个移动步骤,每个移动步骤用两个整数i, j表示,表示位置i的选手移动到位置j, i和j之间有一个空格隔开。

样例输入输出

soring.in

5

20

30

5

15

10

sorting.out

2

2 1

3 5

附原题pdf下载

原题pdf下载(English)

附原题数据下载

原题数据下载(已修改文件名,能被lemon等识别)

题解

本身我不想写,因为我是按照《对一类动态规划问题的研究》(湖南省长沙市第一中学 徐源盛)这篇论文上的思路写的代码,但是网上都没有代码,于是我就写了代码,本着分享的原则,将这篇文章截取下来吧。

同样这题属于当前决策对未来“行动”的费用影响只与当前决策有关的dp题目。







代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cassert>

const int INF = 1e9;
const int MAXN = 1000+10;
typedef std::vector<int> vi;
typedef std::pair<int,int> pii;
typedef std::vector<pii> vpii;

char used[MAXN+1];
int dp[MAXN+1][MAXN+1],prev[MAXN+1][MAXN+1];

int simulate(char *used,vi &p);
void solve(vi &p);

int main() {
freopen("sorting.in","r",stdin);
freopen("sorting.out","w",stdout);
int n;std::map<int,int> byscore;
scanf("%d",&n);
for(int i=0;i<n;i++) {
int val;scanf("%d",&val);
byscore[val]=i;
}
int pos=0;
vi p(n);
for(std::map<int,int> ::reverse_iterator it=byscore.rbegin();it!=byscore.rend();it++,++pos)
p[it->second] = pos;
solve(p);
return 0;
}

int simulate(char *used, vi &p) {
int n = p.size();
int cost = 0;
vpii moves;
for (int i=n-1; i>=0; i--) {
if (used[i])
continue;
vi::iterator it = find(p.begin(),p.end(),i);
int from_pos = distance(p.begin(),it) + 1;
p.erase(it);
it = find(p.begin(),p.end(),i+1);
p.insert(it, i);
int to_pos = distance(p.begin(),it) + 1;
cost += from_pos + to_pos;
moves.push_back(pii(from_pos,to_pos));
}
for (int i=0; i<n; i++)
assert(p[i] == i);
printf("%d\n",(int)moves.size());
for (vpii::iterator it=moves.begin(); it!=moves.end(); ++it)
printf("%d %d\n",it->first,it->second);
return cost;
}

void solve(vi &p) {
int n=p.size();
vi pos(n+1);
p.push_back(n);

for(int i=0;i<=n;i++) pos[p[i]]=i;
for(int i=0;i<n;i++) dp
[i]=INF;
dp

=0;

for(int i=n-1;i>=0;i--) {
int v=1;
for(int j=0;j<pos[i];++j) if(p[j]<i) ++v;
int v2=1;
for(int h=0;h<=n;h++) {
if(p[h]<i) ++v2;
dp[i][h]=dp[i+1][h]+v+v2;
prev[i][h]=h;
}
int add = 0;
for (int k=pos[i]+1; k<=n; k++) {
int tcost = dp[i+1][k]+add;
if (dp[i][pos[i]] > tcost) {
dp[i][pos[i]] = tcost; prev[i][pos[i]] = k;
}
if (p[k]<i) add += (i-p[k]);
}
}
int mincost=INF,ind=-1;
for(int i=0;i<=n;i++) if(dp[0][i]<mincost) {
mincost=dp[0][i];ind=i;
}
for(int i=0;i<n;i++) {
used[i]=(ind==pos[i])?1:0;
ind=prev[i][ind];
}
used
=1;
int tcost = simulate(used,p);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  boi boi2007