Mr_H出了一道信息学竞赛题,就是给 n 个数排序。输入格式是这样的:
试题有若干组数据。每组数据的第一个是一个整数 n,表示总共有 n 个数待排序;接下来 n 个整数,分别表示这n个待排序的数。
现在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个待排序的数。
现在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; }
转载请标明出处:数据(图论)
文章来源: 数据(图论)