201809-4 再賣菜

問題描述

  在一條街上有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的正整數。
  請注意,以上都是給的第二天菜價的範圍,第一天菜價可能會超過此範圍。

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
#define rep(i,a,b) for(int i=a;i<b;++i)


const int N=310;

struct Edge{
	int v,w;
	Edge(int _v=0,int _w=0){
		v=_v,w=_w;
	}
};
vector<Edge>edge[N];


int arr[N],sum[N];

int ans[N];

int dis[N],tim[N],in[N];

void add_edge(int u,int v,int w){
	edge[u].push_back(Edge(v,w));
}

int n;
queue<int> q;
void spfa(){
	in[0]=1;
	q.push(0);
	while(!q.empty()){
		int now=q.front();
		q.pop();
		//printf("now:%d\n",now);
		in[now]=0;
		tim[now]++;
		if(tim[now]>n+1){
			printf("***No Answer!\n");
			break;
		}
		rep(i,0,edge[now].size()){
			Edge e=edge[now][i];
			if(dis[e.v]<dis[now]+e.w){
				dis[e.v]=dis[now]+e.w;
				if(!in[e.v]){
					in[e.v]=1;
					q.push(e.v);
				}
			}
		}
	}
}

int main()
{
	scanf("%d",&n);
	rep(i,1,n+1){
		scanf("%d",&arr[i]);
		sum[i]=sum[i-1]+arr[i];
	}

	add_edge(0,2,2*arr[1]);
	add_edge(2,0,-(2*(arr[1]+1)-1));

	add_edge(n-2,n,arr[n]*2);
	add_edge(n,n-2,-(2*(arr[n]+1)-1));

	for(int i=3;i<=n;i++){
		add_edge(i-3,i,arr[i-1]*3);
		add_edge(i,i-3,-(3*(arr[i-1]+1)-1));
	}

	rep(i,1,n+1)add_edge(i-1,i,1);

	spfa();

	ans[1]=dis[1];
	rep(i,2,n+1){
		ans[i]=dis[i]-dis[i-1];
	}

	rep(i,1,n+1)printf("%d%c",ans[i],i==n?'\n':' ');

    return 0;
}

 

差分約束:

最長路

形式 :   \large d(v) + \alpha <= d(u) + \beta

\large \alpha 和\beta\large \beta 是權值的位置,首先 \large d(u)\large d(v) 這兩個未知數,前面保證沒有負號。

邊權的形式,我們考慮  \large W(u,v),

(1)如果求 未知數符合所有條件的最小值, 就是用最長路, 考慮  \large d(v)>=d(u)+w(u,v),

所以那個  權值就在  小於號那邊

(2)如果求 未知數符合所有條件的最大值,就是用最短路, 考慮 \large d(v)<=d(u)+w(u,v)

那個 權值 就在大於號那邊

 

轉載:https://www.cnblogs.com/zhangmingcheng/p/3929394.html

差分約束系統有兩種方式可以求解,最短路和最長路。當我們把不等式整理成d[a]+w<=d[b]時,我們求最長路。整理成d[a]+w>=d[b]時,我們求最短路。當求最短路時,我們通常要把各點距離初始化爲正無窮,求最短路,把各點距離逐漸減小,直到符合所有不等式。也就是開始 各點不符合條件,後來通過減小變得符合了,所以一定是符合條件的最大值。既然是求最大值,並且是減小各點距離,也就是把各點由數軸的右側向左側拉,所以我 們一定要選擇一個最終在數軸最左側的點,並初始化爲0,把所有正無窮的點拉近到符合不等式。最長路同理。

 

這道題 求 字典序最小,可以理解爲求 最小值, 所以用最長路。

 

注意:

1.列出所有的條件, 包括 每個點都要大於等於某些數值

2.標一個 超級源點 S0

3.而且每個不等式只能是 兩個未知數。 如果多個,像這道題,我們需要引出其他的變量 sum,變成差值來做

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章