【二分搜索】
来源:互联网 发布:沈阳数据恢复中心 编辑:程序博客网 时间:2024/06/05 17:08
/*题意:给出n条线段,以米的单位给出,小数点后两位(精确到厘米),要你对这些线段裁剪,裁剪出m条等长的线段,并且让这些线段尽可能长另外线段的长度不能小于1厘米,如果筹不够m条,输出0.00POJ 1064*/#include<cstdio>#include<cstring>using namespace std;const int maxn=10010;double num[maxn];double eps=1e-5;int main(){ int n,k; while(~scanf("%d%d",&n,&k)){ double maxvalue=0; for(int i=0;i<n;i++){ scanf("%lf",num+i); if(num[i]>maxvalue) maxvalue=num[i]; } double lp=0,rp=maxvalue; while(rp-lp>eps){ double mid=(rp+lp)/2; int sum=0; for(int i=0;i<n;i++){ sum+=num[i]/mid; } if(sum>=k) lp=mid; else rp=mid; } printf("%0.2lf\n",int(rp*100)*0.01); }}
//用整数来二分#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 10010#define MAX 0x3f3f3f3fint a[N];int main(){ int n,m; double len; while(~scanf("%d%d",&n,&m)){ int Max=0; for(int i=0;i<n;i++){ scanf("%lf",&len); a[i]=len*100; Max=max(Max,a[i]); } int low=1,high=Max; int res=0; while(low<=high){ int mid=(low+high)>>1; int sum=0; for(int i=0;i<n;i++) sum+=a[i]/mid; if(sum>=m) res=max(res,mid),low=mid+1; else high=mid-1; } printf("%.2lf\n",(double)res/100.0); }}
/*一条线段上有 n 个点,选取 m 个点,使得相邻点之间的最小距离值最大。POJ 2456*/#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int L,n,m,pos[100005];bool can(int l){ int cnt=1,cur=pos[0]; for(int i=1;i<n;i++){ while(i<n&&pos[i]-cur<l) i++; cur=pos[i]; if(i<n&&++cnt==m) return true; } return false;}int main(){ while(~scanf("%d%d",&n,&m)){ for(int i=0;i<n;i++) scanf("%d",&pos[i]); sort(pos,pos+n); int l=1,r=pos[n-1]-pos[0]; while(l<=r){ int mid=(l+r)/2; if(can(mid)) l=mid+1; else r=mid-1; } printf("%d\n",r); }}
这道题目是一道0-1分数规划求最优值。方法是一个二分搜索+贪心的题目。出这道题目就是告诉大家二分不仅可以查找,还可以搜索一个更优值。要使得单位重量的价值最大,则其最大不超过单个中最大的单位重量的价值,最小当然不小于0.那么我们就这一在0--最大单位重量的价值中间找一个值ans,使得ans为满足题目条件的最大值。如果满足条件,则可以找更大的。设置一个条件。既二分搜索、从n个物品中找k个使得k个的价值和/质量和>=ans为了使得ans尽可能的大,那么这里就要贪心选择。#include<cstdio>#include<algorithm>using namespace std;double wi[10005],vi[10005],pi[10005];int n,k;bool cmp(double a,double b){ return a>b;}int check(double x){ for(int i=0;i<n;i++){//p[i] 代表的是 自己本省的价值-物品重量*最高单价 pi[i]=vi[i]-wi[i]*x; } double y=0; sort(pi,pi+n,cmp); //p[i] 由大到小排序。 for(int i=0;i<k;i++){ y+=pi[i]; } return y>=0;}double reach (double m){// 二分搜索 double l=0,r=m,mid; for(int i=0;i<100;i++){ mid=(r+l)/2; if(check(mid)) l=mid; else r=mid; } return l;}int main(){ while(~scanf("%d%d",&n,&k)){ double ma=0; for(int i=0;i<n;i++){ scanf("%lf%lf",&wi[i],&vi[i]); double ant=vi[i]/wi[i]; if(ant>ma) ma=ant;//选择出单价最高的。 } printf("%0.2lf\n",reach(ma)); }}
/*POJ 3104【题意】:给出n件刚洗完的衣服,每件衣服有一个属性ai,表示改衣服在自然风干的条件需要ti分钟。现在有一台烘干机,每分钟你可以选择把任意一件衣服放进去,那么这件衣服风干的时间就减少k分钟,而每分钟对于不在烘干机的衣服,风干时间都减少1。问最少用多少时间使所有衣服都干了。【题解】:直接二分答案,然后判断答案的正确性。 假设当前二分的答案为 t,那么: 对于ai <= t的衣服,显然让它们自然风干就可以了。 对于ai > t的衣服,我们需要知道该衣服最少用多少次烘干机。 设该衣服用了x1分钟风干,用了x2分钟烘干机。 那么有 x1 + x2 = t 和 ai <= x1 + x2 * k,联立两式可得 x2 >= (ai - t) / (k - 1),即最少使用次数为[(ai - t) / (k - 1)] 的最小上界。 ************************************************ 特别注意 k不能等于1,k等于分母就等于0了 **************************************************** 最后,判断一下总使用次数是否少于 t 即可。*/#include<cstdio>#include<cstring>#define N 100005using namespace std;int time[N];int n,k;bool check(int t){ int cnt=0; for(int i=0;i<n;i++){ if(time[i]<t) continue; //自然风干的时间比其要短,那就让它自然风干 double temp=(double)(time[i]-t)/(k-1);//保证一个物体占用甩干机的时间最短,即为(time[i]-t)/(k-1) cnt+=(int)temp; if(temp-(int)temp>0) ++cnt;//向上取整。如果temp为3.4 ,那么cnt就应该为4 if(cnt>t) return false; } return true;}int main(){ int low,high,mid,ans; while(~scanf("%d",&n)){ high=0;low=0; for(int i=0;i<n;i++){ scanf("%d",&time[i]); if(time[i]>high) high=time[i]; } scanf("%d",&k); if(k==1){ //k不能为1,为1直接输出 printf("%d\n",high); continue; } ans=high; while(low<=high){ mid=low+(high-low)*0.5; if(check(mid)){ ans=mid; high=mid-1; } else low=mid+1; } printf("%d\n",ans); }}
/*求一个有n个正整数组成的序列,给定整数S,求长度最短的连续序列,使得它们的和大于等于SPOJ 3061*/#include<cstdio>#include<cstring>using namespace std;#define maxn 100005int n;int a[maxn],sum[maxn],s;bool check(int x){ for(int i=1;i+x-1<=n;i++){ if(sum[i+x-1]-sum[i-1]>=s) return true; } return false;}int solve(){ int l=1,r=n; while(l<=r){ int mid=(l+r)>>1; if(check(mid)) r=mid-1; else l=mid+1; } return l;}int main(){ int t; scanf("%d",&t); while(t--){ memset(sum,0,sizeof(sum)); scanf("%d%d",&n,&s); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum[i]+=sum[i-1]+a[i];//用sum[i]数组存储从1 到 i 的和 } if(sum[n]<s) printf("0\n"); else printf("%d\n",solve()); }}
/*第二种是假设从s位置开始到t的和大于S,并且s + 1 到t' 的和大于S,则t‘ > t 由此可以跑一次o(n)解决POJ 3061 */#include<cstdio>#include<algorithm>using namespace std;#define maxn 100005int n,S;int a[maxn];void solve(){ int s=1,sum=0,pos=1; int ans=n+1; for(;;s++){ while(sum<=S&&pos<=n) sum+=a[pos++]; if(sum<S) break; sum-=a[s]; ans=min(ans,pos-s); } printf("%d\n",ans==n+1?0:ans);}int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&S); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } solve(); }}
/*题意:n头牛站成线,有朝前有朝后的的,然后每次可以选择大小为k的区间里的牛全部转向,会有一个最小操作m次使得它们全部面朝前方。问:求最小操作m,再此基础上求k。'POJ 3276*/#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int N;int dir[5005];//牛的方向 0:F 1: Bint f[5005];// 区间[i,i+K-1] 是否进行反转//固定K,求相应的最小操作回数//无解返回-1int clac(int K){ memset(f,0,sizeof(f)); int res=0; int sum=0; //f 的和 for(int i=0;i+K<=N;i++){ //计算区间[i,i+K-1] if((dir[i]+sum)%2!=0){ //前端的牛朝后方 res++; f[i]=1; } sum+=f[i]; if(i-K+1>=0){ sum-=f[i-K+1]; } } //检查剩下的牛是否有朝着后方的情况 for(int i=N-K+1;i<N;i++){ if((dir[i]+sum)%2!=0) return -1; if(i-K+1>=0) sum-=f[i-K+1]; } return res;}void solve(){ int K=1,M=N; for(int k=1;k<=N;k++){ int m=clac(k); if(m>=0 &&M>m){ M=m; K=k; } } printf("%d %d\n",K,M);}int main(){ char c; while(~scanf("%d%*c",&N)){ for(int i=0;i<N;i++){ scanf("%c%*c",&c); if(c=='F') dir[i]=0; else dir[i]=1; } solve(); }}
/*题目大意:某人读一本书,要看完所有的知识点,这本书共有P页,第i页恰好有一个知识点ai,(每一个知识点都有一个整数编号)。全书同一个知识点可能会被提到多次,他希望阅读其中一些连续的页把所有知识点都读到,给定每页所读到的知识点,求最少的阅读页数。思路:和上一题一样,也是尺取法的应用。假设从某一页s开始阅读,为了覆盖所有的知识点读到t页,这样的话如果从s+1开始阅读,那么必须读到t'>=t位置,故可以用尺取法。用上Map来统计次数,取出前一项要把对应的知识点的编号次数-1.详见代码。POJ 3320*/#include<cstdio>#include<set>#include<map>#include<algorithm>using namespace std;int P;int a[1000000+10];map<int,int> countx; //知识点---出现次数 映射set<int> all;void solve(){ all.clear(); countx.clear(); for(int i=0;i<P;i++) all.insert(a[i]); int n=all.size(); int s=0,t=0,num=0; int res=P; while(true){ while(t<P&&num<n){ if(countx[a[t++]]++==0){ //出现新的知识点 num++; } } if(num<n) break; res=min(res,t-s); if(--countx[a[s++]]==0){ //某个知识点出现次数为0 num--; } } printf("%d\n",res);}int main(){ while(~scanf("%d",&P)){ for(int i=0;i<P;i++) scanf("%d",&a[i]); solve(); }}
/*题意是说,对四个数列中的数,每一列取一个,求取出来的四个数的和为零的组合个数。POJ 2785*/#include<cstdio>#include<algorithm>#define MAXN 4005using namespace std;int n;int A[MAXN],B[MAXN],C[MAXN],D[MAXN];int CD[MAXN*MAXN];void solve(){ for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ CD[i*n+j]=C[i]+D[j]; } } sort(CD,CD+n*n); long long res=0; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ int cd=-(A[i]+B[j]); res+=upper_bound(CD,CD+n*n,cd)-lower_bound(CD,CD+n*n,cd); } } printf("%lld\n",res);}int main(){ while(~scanf("%d",&n)){ for(int i=0;i<n;i++) scanf("%d%d%d%d",&A[i],&B[i],&C[i],&D[i]); solve(); }}
/*【题目大意】:给出n辆赛车距离终点的距离,每秒钟会前进1米,现在给出m个可以加速k的加速器,每次每辆车只能使用一次加速器,下一个时间点加速器可以重复使用。问所有赛车到达终点的最短时间。POJ 3232*/#include<cstdio>int rider,dis[100005],acc,k;bool check(int m){ long long tot=(long long)acc*m; long long cnt=0; for(int i=0;i<rider;i++){ if(dis[i]<=m) continue; //dis[i] <= m的话该车手自己就可以跑到终点 int tmp=(dis[i]-m)/(k-1)+((dis[i]-m)%(k-1)!=0);//tmp就是当前车手需要的加速次数,向上取整 if(tmp>m) return false; //注意!!这说明即使他一直在加速,一个加速器都无法满足该车手 cnt+=tmp; if(cnt>tot) return false;//一旦超过总加速次数,说明次数不够 } return true;}int main(){ int test; scanf("%d",&test); while(test--){ int maxi=0; scanf("%d",&rider); for(int i=0;i<rider;i++){ scanf("%d",&dis[i]); if(dis[i]>maxi) maxi=dis[i]; } scanf("%d%d",&acc,&k); if(k>1){ int l=1,r=maxi,mid; while(l<=r){ mid=(l+r)>>1; if(check(mid)) r=mid-1; else l=mid+1; //注意!当check失败的时候,意味着需要更大的答案 } printf("%d\n",l); } else printf("%d\n",maxi); }}
0 0
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- 二分搜索
- mysql主从常见问题
- OC基础数据类型-NSDictionary
- C++第11周(春)项目4 - 类族的设计
- FATFS文件系统的移植
- Android编程之SparseArray<E>详解
- 【二分搜索】
- [Asp.net]常见word,excel,ppt,pdf在线预览方案,有图有真相,总有一款适合你!
- 经验之谈
- 网站内容与网站结构是seo终极策略
- select框对div的一些应用
- 品牌诊断研究的内容
- IOS崩溃 异常处理(NSSetUncaughtExceptionHandler)
- oracle 11g 协议适配器错误
- Java英文单词Java基础常见英语词汇