嗯...
题目:
【问题描述】
市中心有一个环形的停车场,编号1到n,现在有m个车要停,停在每个位置会有不同的费用。为了方便,不允许两辆车停在相邻的位置,请问停好所有车的最小花费是多少?
【输入格式】
第一行包含两个正整数n, m,保证n>=2m-1
第二行包含n个正整数,表示停在i位置的费用
【输出格式】
输出一个整数,表示停好所有车的最小花费是多少
【样例输入】
7 3
1 2 3 4 5 6 7
【样例输出】
9
【样例说明】
停在1 3 5
【数据规模与约定】
20% n<=10
40% n<=100
60% n<=1000
100% n<=100000 ai<=10000
分析:
这道题我们首先会考虑贪心。如果没有限制,只需要从小到大贪心即可。由于有了限制,考虑设计能够撤销之前操作。
考虑一个性质的证明:
如果有1 2 3 三个数中选择,如果不选2,那么一定会选1和3。这样的话如果选了2,删除1、3两个节点,把2的权值更改成a[1]+a[3]-a[2],相当于把2修改成了1和3。
优先队列优化贪心可以做到O(nlogn),每次处理后用链表来删除。
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 #define pa pair<int,int> 5 using namespace std; 6 7 int n,m,ans; 8 int vis[10005],a[10005],L[10005],R[10005]; 9 priority_queue<pa,vector<pa>,greater<pa> >q; 10 11 inline void del(int x){ 12 vis[x]=1; 13 R[L[x]]=R[x]; 14 L[R[x]]=L[x]; 15 } 16 17 int main(){ 18 scanf("%d%d",&n,&m); 19 for(int i=1;i<=n;i++){ 20 scanf("%d",&a[i]); 21 L[i]=(i==1)?n:i-1; 22 R[i]=(i==n)?1:i+1; 23 q.push(pa(a[i],i)); 24 } 25 while(m--){ 26 while(vis[q.top().second]) q.pop(); 27 int x=q.top().second; q.pop(); 28 ans+=a[x]; 29 a[x]=a[L[x]]+a[R[x]]-a[x]; 30 del(L[x]); del(R[x]); 31 q.push(pa(a[x],x)); 32 } 33 printf("%d ",ans); 34 return 0; 35 }