HDUOJ 4931 Happy Three Friends
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4931
给出6个数,A可以调整顺序,B先选出首尾两个数,C再从剩下的四个数当中选出3个数,问B选出的两个数之和有没有可能比C选出的3个数之和大。
因为A是帮B的,所以,B如果是聪明人的话,他肯定是从这6个数当中挑出最大的两个数,C也足够聪明,他会从剩下的四个数当中挑3个比较大的数。
那么问题就简单了,现将数据排序,然后比较a[4]+a[5]>a[1]+a[2]+a[3]即可。
亏我一开始想的是枚举全排列。。。。
下面是AC代码:
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,ans[15],flag;
int a[15];//待排列的数存储在此
int main()
{
int t;
cin>>t;
while(t--)
{
for(int i=0;i<6;i++) cin>>a[i];
sort(a,a+6);
if(a[1]+a[2]+a[3]<a[4]+a[5]) cout<<"Grandpa Shawn is the Winner!"<<endl;
else cout<<"What a sad story!"<<endl;
//dfs(0,0);
}
return 0;
}
HDUOJ 4932 Miaomiao's Geometry
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4932
这道题,就是说给出n个数,然后构造一些长度一致的区间,这些区间重叠部分不能大于0,而且这n个数最后都要在某些区间的端点上。求区间长度最大值。
由于以前在《挑战程序设计竞赛》这本书上看过《二分法,不光是求解值!!!》这一章,我第一思路就是想二分长度,然后,对于每个长度以线性的时间计算出是否可行,这种问题一般就是用贪心,仔细思考之后,便可以很容易想出如何用线性的复杂度判断某个区间长度是否可行,贪心思想是这样的,对于每个点,尽量构造区间使得这个点成为构造出区间的右端点,为什么这样是正确的呢?可想而知,这样做比让这个点成为左端点更优优势。自己画画图就明白了。
然后二分枚举区间长度就行了。
代码如下
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<fstream>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<queue>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
const int maxn=105,inf=1<<29;
int dir[][2]={ {0,1},{-1,0},{0,-1},{1,0},{-1,1},{-1,-1},{1,-1},{1,1}};
int n,m,t,a[maxn];
bool judge(double x)
{
double prel=a[0]*1.0;
for(int i=1;i<n;i++)
{
if(a[i]*1.0<prel) return 0;
if(a[i]-x>=prel) prel=a[i]*1.0;
else prel=a[i]*1.0+x;
}
return 1;
}
int main()
{
cin>>t;
while(t--)
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n);
double l=0.0,r=1e10;
for(int i=0;i<100;i++)
{
double mid=(l+r)/2;
if(judge(mid)) l=mid;
else r=mid;
}
printf("%.3lf\n",l);
}
return 0;
}
不过,这个代码提交上去,华丽丽地WA了,思考之下,终于想出了原因, 二分的时候,答案必需要满足单调性啊,这里小的数据不行,大的数据可以行!如 0 1 5 6 10, 3不行,4行。
再细想之,其实区间长度只可能是相邻两个点距离之差,或者这个差的一半,为什么一半也行呢?还是0 1 5 6 10这组数据,比如6和10之间,长度为2也可满足,因为可以构造区间[6,8],[8,10]。
那么有好解决了,答案只可能是2*(n-1)种情况下,n=50,也只不过98中,枚举之,每种判断是否可行依然可用上述贪心思想。
然后是AC了,下面是AC代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<fstream>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<queue>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
const int maxn=105,inf=1<<29;
int dir[][2]={ {0,1},{-1,0},{0,-1},{1,0},{-1,1},{-1,-1},{1,-1},{1,1}};
int n,m,t,a[maxn];
bool judge(int x)
{
int prel=a[0];//perl存的是已经构造好了的区间的右端点
for(int i=1;i<n;i++)
{
if(a[i]<prel) return 0;//如果当前点已经被上一次的区间包含,则这种区间长度是失败的
if(a[i]-x>=prel) prel=a[i];//更新区间右端点
else if(a[i]+x!=a[i+1]) prel=a[i]+x;//如果当前点和下一点不能刚好构造成一个区间则更新右端点
}
return 1;
}
int main()
{
cin>>t;
while(t--)
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i],a[i]*=2;//乘是为了后面能整除,避免用double型带来不必要的误差
sort(a,a+n);
int ans=1;
for(int i=1;i<n;i++)
{
int L=a[i]-a[i-1];
if(judge(L)) ans=max(ans,L);//差
if(judge(L/2)) ans=max(ans,L/2);//差的一半
}
printf("%.3lf\n",ans*1.0/2);
}
return 0;
}