您的位置:首页 > 其它

Ryouko's Memory Note(书本翻页)

2014-06-05 13:15 183 查看

题目大意:

首先输入两个数:n,m。n表示记事本有n页(1~n编号),m表示Ryouko需要的资料在m个页码上(页码可以重复),现在允许Ryouko将一页上的内容搬到另一页上,要求搬完之后使得Ryouko的翻页次数最小。输出最小的翻页次数。

m个页码值分别为a[1]、a[2]、...、a[m],Ryouko总共的翻页次数为


解题思路:

使用容器保存需要翻页的页码之前和之后的页码编号,如果之前或之后的页码和编号和当前的页码编号是一样的,则不需要加入容器中,对于每一个页面编码,都会有一个邻近编号容器adj[i][j],
adjSum[i] 是对于当前页码的邻近数组中翻到当前页面的次数之和,sum为总的翻页次数(搬页之前),adjMinSum[i]是对于当前编号,在邻近表中选个中位数后各个邻近页码编号到中位数的距离。最终结果是sum-adjSum[i]+adjMinSum[i] 的最小值。

例如:

4
  6

1
 2  3  4  3  2



代码:

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define M 100005
#define LL long long
using namespace std;

int a[M]; //页码编号
LL adjSum[M];
LL adjMinSum[M];
vector<int> adj[M];
LL min(LL a, LL b){
if(a < b) return a;
return b;
}
int main(){
int n, m;
LL sum, ans;
while(~scanf("%d%d", &n, &m)){
for(int i=1; i<=m; i++){
scanf("%d", a+i);
}
for(int i=1; i<=m; i++){
if(i != 1 && a[i] != a[i-1]) adj[a[i]].push_back(a[i-1]);
if(i != m && a[i] != a[i+1]) adj[a[i]].push_back(a[i+1]);
}
memset(adjSum, 0 ,sizeof(adjSum));
sum = 0;
for(int i=1; i<=n; i++){
if(adj[i].size()){
for(int j=0; j<adj[i].size(); j++){
adjSum[i] += (i > adj[i][j] ? i-adj[i][j] : adj[i][j]-i);

}
sum += adjSum[i];
}
}
sum /= 2;
ans = sum;
memset(adjMinSum, 0, sizeof(adjMinSum));
for(int i=1; i<=n; i++){
sort(adj[i].begin(), adj[i].end());
}
for(int i=1; i<=n; i++){
int mid = adj[i].size()/2;
for(int j=0; j<adj[i].size(); j++){
adjMinSum[i] += (adj[i][mid] > adj[i][j] ? adj[i][mid]-adj[i][j] : adj[i][j]-adj[i][mid]);
}
ans = min(ans, sum - adjSum[i] + adjMinSum[i]);
}
printf("%lld\n", ans);
for(int i=1; i<=n; i++){
adj[i].clear();
}
}
return 0;
}

注意:

1、数据类型要用到long long 型,不然在计算过程中会出现溢出。

2、容器用完之后要进行clear()操作
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: