Training:搜索入门

HDU 2199:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=20576
输入一个 y ,求使得 8x4+7x3+2x2+3x+6y x 的值, 0x100 。二分查找答案。

#include<cstdio>
#include<cmath>
using namespace std;
const double EPS=1e-5;
inline double f(double x){
    return 8*x*x*x*x+7*x*x*x+2*x*x+3*x+6;
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
        double k;scanf("%lf",&k);
        if(f(0)>k||f(100)<k){
            printf("No solution!\n");
            continue;
        }
        double l=0,r=100,m=50;
        while(fabs(f(m)-k)>EPS){
            if(f(m)>k) r=m;
            else l=m;
            m=(l+r)/2;
        }
        printf("%.4f\n",m);
    }
    return 0;
}

HDU 2899:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=20577
给出函数 F(x)=6x7+8x6+7x3+5x2yx ,输入 y ,求函数最小值。
首先对该函数求导,然后二分查找使导函数为0的值 x0 ,输出 F(x0)

#include<cstdio>
#include<cmath>
using namespace std;
const double EPS=1e-6;
double y;
inline double f(double x){
    return 6*x*x*x*x*x*x*x+8*x*x*x*x*x*x+7*x*x*x+5*x*x-y*x;
}
inline double f2(double x){
    return 42*x*x*x*x*x*x+48*x*x*x*x*x+21*x*x+10*x-y;
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
        scanf("%lf",&y);
        double l=0,r=100,m=50;
        while(fabs(f2(m))>EPS){
            if(f2(m)>0) r=m;
            else l=m;
            m=(l+r)/2;
        }
        printf("%.4lf\n",f(m));
    }
    return 0;
}

HDU 1969:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=23123
给出 n m ,有 n 个蛋糕, m+1 个人,每个蛋糕都可以切开,求每人分一整块蛋糕的最大值。求出蛋糕大小总和,然后进行二分查找,对二分的值进行验证。

#include<cstdio>
#include<cmath>
using namespace std;
const double EPS=1e-6;
const double PI=acos(-1);
const int maxn=10010;
int n,f;
double a[maxn];
inline double c(double r){
    return PI*r*r;
}
bool ok(double x){
    int sum=0;
    for(int i=0;i<n;++i){
        sum+=floor(a[i]/x);
    }
    return sum>=f+1;
}
int main(){
    int t;scanf("%d",&t);
    while(t--){scanf("%d%d",&n,&f);
        double sum=0;
        for(int i=0;i<n;++i){
            scanf("%lf",&a[i]);
            a[i]=c(a[i]);
            sum+=a[i];
        }
        double l=0,r=sum,m=(l+r)/2;
        while(r-l>EPS){
            if(ok(m)) l=m;
            else r=m;
            m=(l+r)/2;
        }
        printf("%.4f\n",m);
    }
    return 0;
}

HDU 1905:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=40853
输入 p a ,如果 p 不为素数且 ap%p==a 输出yes,否则输出no。
2<p10000000001<a<p
首先打出0~ p 的素数表,然后对每个 p 进行素性测试,再用快速幂求 ap%p 判断输出。

#include<cstdio>
#include<cmath>
using namespace std;
typedef long long LL;
const double EPS=1e-6;
const double PI=acos(-1);
const int maxn=100010;
int isp[maxn],pre_p;
bool np[maxn]={true,true};
void pre(){
    for(int i=2;i<maxn;++i){
        if(!np[i]) isp[pre_p++]=i;
        for(int j=0;j<pre_p&&i*isp[j]<maxn;++j){
            np[i*isp[j]]=true;
            if(!(i%isp[j])) break;
        }
    }
    return;
}
bool isprime(LL n){
    double k=sqrt(n);
    for(int i=0;isp[i]<=k;++i)
        if(n%isp[i]==0) return false;
    return true;
}
LL modexp(LL a,LL b,LL mod){
    LL cur=1,tmp=a;
    while(b){
        if(b&1) cur=cur*tmp%mod;
        tmp=tmp*tmp%mod;
        b>>=1;
    }
    return cur;
}
int main(){
    pre();
    LL n,a;
    while(~scanf("%lld%lld",&n,&a)&&(n||a)){
        if(isprime(n)){printf("no\n");continue;}
        else{
            if(modexp(a,n,n)==a) printf("yes\n");
            else printf("no\n");
        }
    }
    return 0;
}

HDU 2648:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=18590
给出多个店的价格和每周上涨的价格,输出每周memory这家店的价格排名。

#include<iostream>
#include<string>
#include<map>
using namespace std;
map<string,int> a;
int main(){
    int n,m,k;
    while(cin>>n){
        a.clear();
        string s;
        for(int i=0;i<n;++i) cin>>s,a[s]=0;
        cin>>m;
        for(int i=0;i<m;++i){
            int aim=0,ans=1;
            for(int j=0;j<n;++j){
                cin>>k>>s;
                a[s]+=k;
                if(s=="memory") aim=a[s];
            }
            for(map<string,int>::iterator it=a.begin();it!=a.end();++it)
                if(it->second>aim) ++ans;
            cout<<ans<<endl;
        }
    }
    return 0;
}

HDU 2446:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=11791
一开始枚举前缀和再进行二分查找。结果内存超限了。
不会优化,看了结题报告才知道可以用公式做。
http://blog.csdn.net/zxy_snow/article/details/6721066
公式: (n3n)6

//原来的代码:
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=3810779;
LL a[maxn],sum[maxn];
int main(){
    for(int i=1;i<maxn;++i) a[i]=a[i-1]+i,sum[i]=sum[i-1]+a[i];
    int t;scanf("%d",&t);
    while(t--){
        LL n;scanf("%lld",&n);
        int l=0,r=0,c=0;
        l=int(upper_bound(sum,sum+maxn,n)-sum);
        if(sum[l-1]==n) --l;
        n-=sum[l-1];
        r=int(upper_bound(a,a+maxn,n)-a);
        if(a[r-1]==n) --r;
        c=int(n-a[r-1]);
        printf("%d %d %d\n",l,r,c);
    }
    return 0;
}

HDU 2141:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=18481
给出 a b c 三个数组,然后输入 s ,输出是否存在 ai bj ck 使得 ai+bj+ck=s
对两个数组进行预处理,然后在另一个中枚举,在预处理后的数组中二分查找。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=550;
LL a[maxn],b[maxn],c[maxn],k[maxn*maxn];
int main(){
    int l,n,m,t=0;
    while(~scanf("%d%d%d",&l,&n,&m)){
        for(int i=0;i<l;++i) scanf("%lld",&a[i]);
        for(int i=0;i<n;++i) scanf("%lld",&b[i]);
        for(int i=0;i<m;++i) scanf("%lld",&c[i]);
        int pos=0;
        for(int i=0;i<l;++i)
            for(int j=0;j<n;++j)
                k[pos++]=a[i]+b[j];
        sort(c,c+m),sort(k,k+pos);
        printf("Case %d:\n",++t);
        int s;scanf("%d",&s);
        while(s--){
            LL x;scanf("%lld",&x);
            bool flag=false;
            for(int i=0;i<m;++i)
                if(binary_search(k,k+pos,x-c[i])){flag=true;break;}
            puts(flag?"YES":"NO");
        }
    }
    return 0;
}

HDU 2298:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=19904
给出物体下落点的坐标和发射初始速度,求角度。物理题推公式求根。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double g=9.8;
const double PI=acos(-1);
int main(){
    int t;scanf("%d",&t);
    while(t--){
        double x,y,v;
        scanf("%lf%lf%lf",&x,&y,&v);
        double a=g*x*x,b=-2*v*v*x,c=2*v*v*y+g*x*x,dt=b*b-4*a*c;
        if(dt<0){printf("-1\n");continue;}
        double x1=atan((-1*b+sqrt(dt))/(2*a)),x2=atan((-1*b-sqrt(dt))/(2*a)),ans=PI/2;
        if((x1<0||x1>PI/2)&&(x2<0||x2>PI/2)){printf("-1\n");continue;}
        if(x1>=0&&x1<=PI/2) ans=min(ans,x1);
        if(x2>=0&&x2<=PI/2) ans=min(ans,x2);
        printf("%.6f\n",ans);
    }
    return 0;
}

HDU 2289:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=15721
给出一个圆台容器,给出水的体积,求水在圆台容器中的体积。
利用圆台体积公式,二分高度,输出。

#include<cstdio>
#include<cmath>
using namespace std;
const double PI=acos(-1);
const double EPS=1e-7;
double GetVolume(double r,double R,double h,double H)
{
    double u = h/H*(R-r) + r;
    return PI/3*(r*r+r*u+u*u)*h;
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
        double r,R,H,V;scanf("%lf%lf%lf%lf",&r,&R,&H,&V);
        double hl=0,hr=H,h=(hl+hr)/2;
        while(hr-hl>EPS){
            if(GetVolume(r,R,h,H)>V) hr=h;
            else hl=h;
            h=(hl+hr)/2;
        }
        printf("%.6f\n",h);
    }
    return 0;
}

HDU 1010:
http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=16336
给出一个地图,问能不能在 t 步之内从起点走到终点,不能重复走过同一个格子。
因为是恰好走到,所以是DFS的题,而不是BFS。
要进行剪枝,否则会超时。首先进行奇偶性剪枝,起点终点间的距离要和 t 的奇偶性相同,然后再查找的过程中如果当前点到终点的距离小于剩余时间就回溯。

#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=10;
const int go[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
char g[maxn][maxn];
bool vis[maxn][maxn];
int n,m,t,bx,by,ex,ey;
bool dfs(int x,int y,int cur){
    if(cur==t){
        if(x==ex&&y==ey) return true;
        return false;
    }
    if(abs(x-ex)+abs(y-ey)>t-cur) return false;
    for(int i=0;i<4;++i){
        int a=x+go[i][0],b=y+go[i][1];
        if(!vis[a][b]&&(g[a][b]=='.'||g[a][b]=='D')){
            vis[a][b]=true;
            if(dfs(a,b,cur+1)) return true;
            vis[a][b]=false;
        }
    }
    return false;
}
int main(){
    while(~scanf("%d%d%d",&n,&m,&t)&&!(!n&&!m&&!t)){
        for(int i=1;i<=n;++i){
            scanf("%s",g[i]+1);
            for(int j=1;j<=m;++j){
                if(g[i][j]=='S') bx=i,by=j;
                if(g[i][j]=='D') ex=i,ey=j;
            }
        }
        if(abs(bx-ex)+abs(by-ey)>t||(abs(bx-ex)+abs(by-ey)+t)&1){puts("NO");continue;}
        memset(vis,0,sizeof(vis));
        vis[bx][by]=true;
        puts(dfs(bx,by,0)?"YES":"NO");
    }
    return 0;
}

你可能感兴趣的:(搜索,ACM,HDU)