poj 1700 过河问题 贪心法

#include <iostream>

#include <algorithm>

using namespace std;



/*

贪婪法:

1)当人数<3时:直接过

2)当人数=3时:假设为a,b,c.(升序)

如果用最小的来送:c+a+b=c+b+a

如果大的一起过:c+b+b=c+2b.

所以这个时候用小的来送.

3)当人数=4时,a,b,c,d(升序)

如果用最小的来送:d+a+c+a+b=d+c+b+2a

如果先让最小的两个过河,再让其中一个回来,

让最大的两个过河,再让前一步过去留下的那个回来,

再让最小的2个过河

也就是说小的两个过去2次,再单独回来一次.

2b+b+a+d=d+3b+a 

当d+c+b+2a<=d+3b+a时,也就是c-2b+a<=0时,第一种方法过.

否则用另外一种办法

4)当人数>4时,a,b,..,c,d(升序)

过去,回来,过去,回来(船要回来),让最大的2个过去.

很笨的时间是d+c+c+a=d+2c+a(所有时间都写出来后会发现时最慢的)

如果让最小的来送:d+a+c+a=d+c+2a

否则:b+b+a+d=d+2b+a

如果d+c+2a<=d+2b+a,也就是c-2b+a<=0时,第一种方法过

*/



int main()

{

	//freopen("in.txt", "r", stdin);

	int p[1005],t,n;

	cin>>t;

	while(t--)

	{

		cin>>n;

		int i = 0;

		while(i < n)

			cin>>p[i++];

		sort(p, p + n);//左闭右开

		int sum = 0;

		while(n)

		{

			if(n == 1)

			{

				sum += p[0];

				n = 0;

			}

			else if(n == 2)

			{

				sum += p[1];

				n = 0;

			}

			else if(n == 3)

			{

				sum += (p[0] + p[1] + p[2]);

				n = 0;

			}

			else if(n == 4)

			{

				if(p[2] - 2 * p[1] + p[0] <= 0)

					sum += (p[3] + p[2] + p[1] + 2 * p[0]);

				else

					sum += (p[3] + 3 * p[1] + p[0]);

				n = 0;

			}

			else

			{

				if(p[n - 2] - 2 * p[1] + p[0] <= 0)

					sum += (p[n - 1] + p[n - 2] + 2 * p[0]);

				else

					sum += (p[n - 1] + 2 * p[1] + p[0]);

				n -= 2;

			}

		}

		cout<<sum<<endl;

	}



	return 0;

}

你可能感兴趣的:(poj)