ccf 201809-4 再卖菜

201809-4
试题名称:再卖菜
时间限制:1.0s
内存限制:256.0MB
问题描述:

问题描述

  在一条街上有n个卖菜的商店,按1至n的顺序排成一排,这些商店都卖一种蔬菜。
  第一天,每个商店都自己定了一个正整数的价格。店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商店的价格调整自己的价格。具体的,每家商店都会将第二天的菜价设置为自己和相邻商店第一天菜价的平均值(用去尾法取整)。
  注意,编号为1的商店只有一个相邻的商店2,编号为n的商店只有一个相邻的商店n-1,其他编号为i的商店有两个相邻的商店i-1和i+1。
  给定第二天各个商店的菜价,可能存在不同的符合要求的第一天的菜价,请找到符合要求的第一天菜价中字典序最小的一种。
  字典序大小的定义:对于两个不同的价格序列(a1, a2, ..., an)和(b1, b2, b3, ..., bn),若存在i (i>=1), 使得ai<bi,且对于所有j<i,aj=bj,则认为第一个序列的字典序小于第二个序列。

输入格式

  输入的第一行包含一个整数n,表示商店的数量。
  第二行包含n个正整数,依次表示每个商店第二天的菜价。

输出格式

  输出一行,包含n个正整数,依次表示每个商店第一天的菜价。

样例输入

8
2 2 1 3 4 9 10 13

样例输出

2 2 2 1 6 5 16 10

数据规模和约定

  对于30%的评测用例,2<=n<=5,第二天每个商店的菜价为不超过10的正整数;
  对于60%的评测用例,2<=n<=20,第二天每个商店的菜价为不超过100的正整数;
  对于所有评测用例,2<=n<=300,第二天每个商店的菜价为不超过100的正整数。
  请注意,以上都是给的第二天菜价的范围,第一天菜价可能会超过此范围。

解题思路:这道题可以利用差分约束系统来求解。差分约束系统使用的条件是二元一次不等式,我们将xi-2+xi-1+xi的值看成是一个整体,即dst[i]-dst[i-3];利用题目中的条件,我们可以写出不等式组如下:

另x为第一天的售价,y为第二天的售价,可得

2*y1<=x1+x2<=2*y1+1;

3*y2<=x1+x2+x3<=3*y2+2;

3*y3<=x2+x3+x4<=3*y3+2;

.......

2*yn<=xn-1+xn<=2*yn+1;

由于题目中要求的是字典序最小的,如果选用最短路求解的话,遍历的是最后一组解,是字典序最大的;所以应用最长路求解,写出不等式,spfa与最短路的求解相似

满分代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=310;
int a[N];//代表第二天的菜价 
int dst[N],vst[N];//dst[n]-dst[n-1]=a[n]; 
int n;//n个商店 
//利用邻接表来进行存储
//结构体的存储
struct edge{
	int v,next,w;
}e[2006];
int p[N],eid;
void init(){//初始化 
	memset(p,-1,sizeof(p));
	eid=0;
}
 
//邻接表的插入操作
void insert(int u,int v,int w){
	e[eid].v=v;
	e[eid].w=w;
	e[eid].next=p[u];
	p[u]=eid++;
} 
void spfa(){
	queue<int>q;
	for(int i=0;i<=n;i++){
		dst[0]=0;
		vst[0]=0;
	}
	q.push(0);
	vst[0]=1;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		vst[x]=0;
		for(int i=p[x];i!=-1;i=e[i].next){
			int xx=e[i].v;
			if(dst[x]+e[i].w>dst[xx]){
				dst[xx]=dst[x]+e[i].w;
				if(!vst[xx]){
					q.push(xx);
					vst[xx]=1;
				}
			}
		}
	}
	return;
	
}
//利用最短路求解时dst[j]有最大值
//利用最长路求解时dst[j]有最小值 
int main(){
	init();
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=0;i<n-2;i++){//插入有向边 
		insert(i+3,i,-(3*a[i+2]+2));
		insert(i,i+3,3*a[i+2]);
		
	}
	//单独处理dst[2]即a1与a2的的情况
	insert(2,0,-(2*a[1]+1));
	insert(0,2,2*a[1]); 
	//单独处理dst[n]的情况
	insert(n,n-2,-(2*a[n]+1));
	insert(n-2,n,2*a[n]);
	//每个值都需要大于等于1
	for(int i=1;i<=n;i++){
		insert(i-1,i,1);
	} 
	spfa();
	cout<<dst[1];
	for(int i=2;i<=n;i++){
		cout<<" ";
		cout<<dst[i]-dst[i-1];
	}
	return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值