Mr_H出了一道信息学竞赛题,就是给 n 个数排序。输入格式是这样的:
试题有若干组数据。每组数据的第一个是一个整数 n,表示总共有 n 个数待排序;接下来 n 个整数,分别表示这n个待排序的数。
例如:3 4 2 –1 4 1 2 3 4,就表示有两组数据。第一组有3个数(4,2,-1),第二组有4个数(1,2,3,4)。可是现在Mr_H做的输入数据出了一些问题。例如:2 1 9 3 2 按理说第一组数据有2个数(1,9),第二组数据有3个数,可是“3”后面并没有出现三个数,只出现了一个数“2”而已!
现在Mr_H需要对数据进行修改,改动中“一步”的含义是对文件中的某一个数+1或-1,写个程序,计算最少需要多少步才能将数据改得合法。
【输入格式】
第一行一个整数m,表示Mr_H做的输入数据包含的整数个数。第二行包含m个整数a[i],每个整数的绝对值不超过10000。
【输出格式】
一个整数,表示把数据修改为合法的情况下,最少需要多少步。
【输入样例】
【样例1】
4
1 9 3 2
【样例2】
10
4 4 3 5 0 -4 -2 -1 3 5
【输出样例】
【样例1】
2
【样例1】
3
【数据范围】
对于20%的数据,m<=10, |a[i]|<=5;
对于60%的数据,m<=5000, |a[i]|<=10000
试题有若干组数据。每组数据的第一个是一个整数 n,表示总共有 n 个数待排序;接下来 n 个整数,分别表示这n个待排序的数。
例如:3 4 2 –1 4 1 2 3 4,就表示有两组数据。第一组有3个数(4,2,-1),第二组有4个数(1,2,3,4)。可是现在Mr_H做的输入数据出了一些问题。例如:2 1 9 3 2 按理说第一组数据有2个数(1,9),第二组数据有3个数,可是“3”后面并没有出现三个数,只出现了一个数“2”而已!
现在Mr_H需要对数据进行修改,改动中“一步”的含义是对文件中的某一个数+1或-1,写个程序,计算最少需要多少步才能将数据改得合法。
【输入格式】
第一行一个整数m,表示Mr_H做的输入数据包含的整数个数。第二行包含m个整数a[i],每个整数的绝对值不超过10000。
【输出格式】
一个整数,表示把数据修改为合法的情况下,最少需要多少步。
【输入样例】
【样例1】
4
1 9 3 2
【样例2】
10
4 4 3 5 0 -4 -2 -1 3 5
【输出样例】
【样例1】
2
【样例1】
3
【数据范围】
对于20%的数据,m<=10, |a[i]|<=5;
对于60%的数据,m<=5000, |a[i]|<=10000
对于100%的数据,m<=100000, |a[i]|<=10000
分析:
1.当a[i]>=0,i号节点可以不加修改地到达i+a[i]+1号节点,于是连一条从i出发的权值为0的有向边,注意i+a[i]+1可以大于m+1;这一步当a[i]<0时可以直接忽略(思考为什么)
2.任意一个节点向左或向右一步都相当于是一次操作,于是左右各连一条权值为1的无向边;这一步当a[i]<0时不能忽略(思考为什么)
3.a[1]不能小于0。所以当a[1]小于0时,答案直接加上-a[1]并把a[i]变为0,继续后面的操作(思考为什么变成0就可以了)
4.a[1]和a[2]之间一定不能连无向边(即因为操作而连的边),举几个例子就知道了
5.注意细节:因为可能有些点连到了大于m+1的点,m+1可能通过这些大于它的点到达,所以大于m+1的点也需要左右连一条权值为1的无向边
6.当边连好之后,求出1节点到m+1节点的最短路就可以了
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int maxm=100005;
const int INF=2000000000;
int m,last[maxm*2],np=0;
struct edge{int to,pre,w;}E[maxm*5];
struct data
{
int id,d;
friend bool operator < (data a,data b) {return a.d>b.d;}
};
char c;int flag;
inline void scan(int &x)
{
flag=1;
while((c<'0'||c>'9')&&c!='-') c=getchar();
if(c=='-') flag=-1,c=getchar();
for(x=0;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
x*=flag;
}
inline void addedge(int u,int v,int w)
{
E[++np]=(edge){v,last[u],w};
last[u]=np;
}
int dis[maxm*2],done[maxm*2];
inline int Dijkstra()
{
priority_queue<data>pq;
for(int i=0;i<=maxm+20000;i++) dis[i]=INF;
dis[1]=0;
pq.push((data){1,0});
while(!pq.empty())
{
data t=pq.top();
pq.pop();
int i=t.id,d=t.d;
if(done[i]) continue;
done[i]=1;
for(int p=last[i];p;p=E[p].pre)
{
int j=E[p].to,w=E[p].w;
if(dis[j]>dis[i]+w)
{
dis[j]=dis[i]+w;
pq.push((data){j,dis[j]});
}
}
}
return dis[m+1];
}
int main()
{
// freopen("in.txt","r",stdin);
scan(m);
int k=0,x;
scan(x);
if(x<0) addedge(1,2,0),k-=x;//判断a[1]的正负
else addedge(1,x+2,0);
for(int i=2;i<=m;i++)
{
scan(x);
if(x>=0) addedge(i,i+x+1,0);//不加修改地到达
addedge(i+1,i,1);//左右修改一次
addedge(i,i+1,1);
}
for(int i=m+1;i<=m+20000;i++) addedge(i,i+1,1),addedge(i+1,i,1);//大于m+1的点
int ans=k+Dijkstra();
printf("%d",ans);
return 0;
}