题目链接:
http://acm.nyist.net/JudgeOnline/problem.php?pid=71
描述
进行一次独木舟的旅行活动,独木舟可以在港口租到,并且之间没有区别。一条独木舟最多只能乘坐两个人,且乘客的总重量不能超过独木舟的最大承载量。我们要尽量减少这次活动中的花销,所以要找出可以安置所有旅客的最少的独木舟条数。现在请写一个程序,读入独木舟的最大承载量、旅客数目和每位旅客的重量。根据给出的规则,计算要安置所有旅客必须的最少的独木舟条数,并输出结果。
输入
第一行输入s,表示测试数据的组数;
每组数据的第一行包括两个整数w,n,80<=w<=200,1<=n<=300,w为一条独木舟的最大承载量,n为人数;
接下来的一组数据为每个人的重量(不能大于船的承载量);
输出
每组人数所需要的最少独木舟的条数。
样例输入
3 85 6 5 84 85 80 84 83 90 3 90 45 60 100 5 50 50 90 40 60 |
样例输出
5 3 3 |
算法思想:
这是个简单的贪心算法,每次从左往右扫描,每次选取最合适的一对进行搭配坐船(重量和尽可能接近船的承载重量),如果没有合适的就一个人搭载一只船。这里设置了一个标志位用于标识是否已经过河。
最优代码算法思想,先将体重进行排序,用i指向未过河的第一个人,第k指向未过河的最后一个人:
当2 * p[i] <= w时:
当p[k] + p[i] > w 且 i< k时,表明第k个人与重量最小的人搭配重量都大于w,故第k个人需要单独一只船,count++,–k;
当i==k时,表示只剩一个人未过河,则count++;
当p[k] + p[i] < w时,cout++,++i,表示第i个与第k个最搭配伙伴;
当2 * p[i] > w时,说明第i个与后面的人搭配,重量肯定大于w;
当i == k时,count++;
当i < k时,count += 2,k–,i++。
源代码
#include <iostream>
#include <vector>
using namespace std;
typedef struct {
int w;
int flage;
}PERSON,*PPERSON;
int main()
{
int s, w, n, ans;
vector<PERSON> vec;
PERSON person;
cin >> s;
while (s--)
{
vec.clear();
ans = 0;
cin >> w >> n;
for (int i = 0; i < n; i++)
{
cin >> person.w;
person.flage = 1;
vec.push_back(person);
}
int pos;
for (int i = 0; i < n; i++)
{
pos = i;
//temp为第i个人的重要
int temp = vec[i].w;
if (vec[i].flage && vec[i].w < w) //当该人未过河,且其重量小于船的承载重量时
{
vec[i].flage = 0; //将该人的状态标识更新为0,表示已过河
for (int j = i + 1; j < n; j++) //循环遍历查找最优搭配的过河伙伴
{
if (vec[j].flage)
{
int curr = vec[i].w + vec[j].w;
if (temp <= w && curr <= w && temp < curr)
{
temp = curr;
pos = j;
}
}
}
vec[pos].flage = 0; //如果有合适的最优伙伴,则更新pos,如果没有合适的伙伴,pos仍为i,并将第pos个人的状态更新为0
ans++;
}
else if (vec[i].w == w) //当第i个人的重量正好为w时,表示不需寻找最优伙伴
{
ans++;
}
}
cout << ans << endl;
}
return 0;
}
最优源代码
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int v;
cin>>v;
while(v--)
{
int w,n,*p,t;
cin>>w>>n;
p=new int[n];
for(int i=0;i<n;i++)
{cin>>t;p[i]=t;}
sort(p,p+n);//从小到大进行排序
int i=0,k=n-1,count=0;//用i指向第一个,k指向最后一个,count用于计数所需船只
while(i<=k)
{
if(2*p[i]<=w)//当2*p[i]<=w时,去查询最优搭档
{
while((p[i]+p[k]>w)&&(i<k))//当(p[i]+p[k]>w)&&(i<k),表明第k个人必须得一个人坐船,count++,--k
{count++;--k;}
if(i==k)
count++;
else //当p[i]+p[k]<w,表明第i个与第k个是最优搭配,故count++,--k,++i
{count++;--k;}
}
else//当2*p[i]>w时,表明只能一人一船
{
if(i==k)
count++;
else
{count+=2;--k;}
}
++i;
}
cout<<count<<endl;}
return 0;
}
算法复杂度:
由源代码可知,第一种算法时间复杂度为O(n^2),第二种算法时间复杂度为O(n),但是排序的时间复杂度为O(nlog(n)),故第二种时间复杂度为O(nlog(n))。