POJ 2573: AD HOC&貪心


——AD HOC
——貪心
原題傳送門

前言

這是一道有紀念意義的題目.
在心裏默默地說:

一定要好好write哦!
“I will.”

Description

n people wish to cross a bridge at night.
A group of at most two people may cross at any time, and each group must have a flashlight.
Only one flashlight is available among the n people, so some sort of shuttle arrangement must be arranged in order to return the flashlight so that more people may cross.
Each person has a different crossing speed; the speed of a group is determined by the speed of the slower member. Your job is to determine a strategy that gets all n people across the bridge in the minimum time.

題目大意

  1. 有n個人想要過橋.
  2. 任何時刻橋上最多有2個人.
  3. 過橋需要手電筒,而n個人只有1個手電筒,所以到對岸的人需要回來傳遞手電筒.
  4. 兩個人過橋的時間是過橋較慢的那個人過橋所需時間.
  5. 已知所有人的過橋時間T1—Tn ,求所有人過橋所需的最小時間.

Data

Input
The first line of input contains n, followed by n lines giving the crossing times for each of the people.
Output
The first line of output must contain the total number of seconds required for all n people to cross the bridge.
The following lines give a strategy for achieving this time.
Each line contains either one or two integers, indicating which person or people form the next group to cross.
(Each person is indicated by the crossing time specified in the input. Although many people may have the same crossing time the ambiguity is of no consequence.)
Note that the crossings alternate directions, as it is necessary to return the flashlight so that more may cross.
If more than one strategy yields the minimal time, any one will do.
1<=n<=1000 Ti<=100

	Sample Input
	4
	1
	2
	5
	10
	Sample Output
	17
	1 2
	1
	5 10
	2
	1 2

數據

輸入:
第一行一個正整數 n.
第二到第 n+1 行,n 個正整數 Ti 表示第 i 個人的過橋時間.
輸出:
第一行一個正整數,表示所有人過橋的最小時間.
接下來若干行,表示每一次過橋的人過橋 所用時間 ,中間1個空格隔開.

思路

綜合了AD HOC和貪心的一道好題.
因爲要輸出人員過橋的時間,
所以不需要考慮人員的序號,只需注意他們的大小關係.
So,我們可以對 T 排序.
接下來,我們正式考慮此題.
爲了方便敘述,我們分幾個模塊進行分析.



形成算法


設排完序的時間序列爲A
那麼下面考慮An如何過橋.
因爲An過橋最慢,所以無論如何過橋,時間都是An.
既然這樣了,我們應該選擇最快的人傳遞手電筒.
而我們應該儘量讓兩個人過橋.
所以,一個貪心算法應運而生.


構造模型


所以,我們考慮最快的兩個人A1,A2(下稱A,B)和最慢的兩個人An,An-1(下稱a,b).
我們有兩種方案:

  1. 用A傳遞手電筒幫助a,b過橋.
    先讓A,a過橋,用時爲a,A再回來,用時爲A,再讓A,b過橋,用時爲b,A再回來,用時爲A.
    總用時爲a+b+2*A
  2. 用A,B傳遞手電筒幫助a,b過橋.
    先讓A,B過橋,用時爲B,再讓A回來,用時爲A,再讓a,b過橋,用時爲a,B再回來,用時爲B.
    總用時爲a+A+2*B
    我們比較這兩種方案,取最優(最小)方案即可.
    這樣,我們每次可以讓兩個人以最優策略過橋.

邊界條件


通過上述方法,我們每次能將人員個數減少2.
那麼,什麼時候可以停止呢?只有一個人的時候停止顯然是不夠的.
經過分析,可以得到:

  1. 2個人是合法的終止條件,因爲兩個人可以一次過橋,屬於合法條件.
  2. 3個人是合法的終止條件,因爲貪心策略裏可以省略最後一步,以達到3人過橋的效果.

所以,
當剩餘2個人時,時間爲最慢的那一個(A2),時間爲A2.
當剩餘3個人時,讓最快的人(A1)和最慢的人(A3)過橋,A1再回來,再與A2過橋,總時間爲A1+A2+A3.
這樣,我們就可以正式寫出代碼了.


注意事項


  1. 題目要求輸出方案,可以用一個V數組記錄.
    vector會更方便,但是push_back() 比較長,容易污染代碼出錯.
    不妨用V[0]記錄這次過橋是1個人還是2個人.
  2. n=1時,算法沒有關於這組數據的闡述,可以加一組特判.
    // 可憐我在這上面 WA了好幾次 ?

不理解的地方可以看代碼.

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int N=1010;
int n;
int a[N];
int v[2*N][3]; 
int main()
{
	int cnt=0;
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	//n=1時的特判
	if (n==1)
	{
		printf("%d\n%d",a[1],a[1]);
		return 0;
	}
	sort(a+1,a+n+1);
	int ans=0,i;
	for (i=n;i>3;i-=2)
	{
		//if 是貪心抉擇
		if (a[i-1]+a[1]<2*a[2]) 
		{
			//A[i-1,i,1]的方案1
			ans+=a[i-1]+a[i]+2*a[1];
			//V數組記錄方案
			v[++cnt][0]=2,v[cnt][1]=a[1],v[cnt][2]=a[i-1];
			v[++cnt][0]=1,v[cnt][1]=a[1];
			v[++cnt][0]=2,v[cnt][1]=a[1],v[cnt][2]=a[i];
			v[++cnt][0]=1,v[cnt][1]=a[1];
		}
		else
		{
			//A[1,2,i]的方案2
			ans+=a[1]+a[i]+2*a[2];
			//V數組記錄方案
			v[++cnt][0]=2,v[cnt][1]=a[1],v[cnt][2]=a[2];
			v[++cnt][0]=1,v[cnt][1]=a[1];
			v[++cnt][0]=2,v[cnt][1]=a[i-1],v[cnt][2]=a[i]; 
			v[++cnt][0]=1,v[cnt][1]=a[2]; 
		} 
	}
	//邊界條件判定
	if (i==3)//有三個人,分別爲A[1,2,3]
	{
		ans+=a[1]+a[2]+a[3];
		v[++cnt][0]=2,v[cnt][1]=a[1],v[cnt][2]=a[3];
		v[++cnt][0]=1,v[cnt][1]=a[1];
		v[++cnt][0]=2,v[cnt][1]=a[1],v[cnt][2]=a[2];
	}
	if (i==2)//有兩個人,分別爲A[1,2]
	{
		ans+=a[2];
		v[++cnt][0]=2,v[cnt][1]=a[1],v[cnt][2]=a[2];
	}
	//輸出方案
	printf("%d\n",ans);
	for (int i=1;i<=cnt;i++)
	{
		for (int j=1;j<=v[i][0];j++)
			printf("%d ",v[i][j]);
		puts("");
	}
	return 0;
}

後記

本題主要考察貪心和思維寬度.
只使用貪心可能不足以解決本題,還需稍加思考.
與其說是貪心,不如說是IQ 1000題.

感謝奆老關注 qwq ?

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