NOIP2014提高组DAY1题解

版权声明:欢迎转载+原文章地址~ https://blog.csdn.net/Hi_KER/article/details/82529104

T1:生活大爆炸版石头剪刀布

考察知识:模拟

算法难度:X+ 实现难度:XX

分析:

按照题目描述模拟即可,代码应该很易懂的:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,na,nb,a[205],b[205],A,B;
int calc(int x,int y){//所有情况
    if(x==0) switch(y){
        case 2:case 3: return 1;
        default :return 0;
    }
    else if(x==1) switch(y){
        case 0:case 3: return 1;
        default :return 0;
    }
    else if(x==2) switch(y){
        case 1: case 4: return 1;
        default :return 0;
    }
    else if(x==3) switch(y){
        case 2: case 4: return 1;
        default :return 0;
    }
    else if(x==4) switch(y){
        case 0: case 1: return 1;
        default :return 0;
    }
}
int main(){
    scanf("%d%d%d",&n,&na,&nb);
    for(int i=0;i<na;i++) scanf("%d",a+i);
    for(int i=0;i<nb;i++) scanf("%d",b+i);
    for(int i=0;i<n;i++){
        A+=calc(a[i%na],b[i%nb]);//直接调用计算函数即可
        B+=calc(b[i%nb],a[i%na]);
    }
    printf("%d %d\n",A,B);
    return 0;
}

T2:联合权值

考察知识:图论,树

算法难度:XXX 实现难度:XXX

讲解+代码:见https://blog.csdn.net/Hi_KER/article/details/79761399

我半年前写的,还是勉强能看懂的。

T3:飞扬的小鸟

考察知识:动态规划,动态规划的优化

算法难度:XXX+ 实现难度:XXX+

分析:

定义状态方程:f(i,j)表示小鸟飞到坐标(i,j)需要的最少点击次数

边界:f(0,j)=0\,\,(0<j<=n) \,\,\,\,f(i,j)=\infty \,\,(i>0)

状态转移方程:f(i,j)=min\begin{Bmatrix} f(i-1,j+Y_i)&& \\ f(i-1,j-X_i\times c)&& \end{Bmatrix}

代码实现:

1.这种方法是用当前状态推后面状态,时间复杂度O(nmc),超时,80分

    for(int i=0;i<n;i++)
    for(int h=L[i]+1;h<=H[i]-1;h++){
        if(h>Y[i]) f[i+1][h-Y[i]]=min(f[i][h],f[i+1][h-Y[i]]);
        for(int c=1;;c++){
            if(h+c*X[i]>=m){
                f[i+1][m]=min(f[i+1][m],f[i][h]+c);
                break;
            }
            f[i+1][h+c*X[i]]=min(f[i+1][h+c*X[i]],f[i][h]+c);
        }
    }

2.背包优化

代码实现比方法1复杂,时间复杂度O(nm),可以AC

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=10002,inf=16000000;
int n,m,k,f[10002][2002/*注意*/],X[maxn],Y[maxn],L[maxn],H[maxn];
bool pipe[maxn];
void ready(){//预处理
    int pos,l,h;
    memset(f,1,sizeof(f));
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) scanf("%d%d",X+i,Y+i),H[i]=m+1;
    for(int i=1;i<=k;i++) scanf("%d%d%d",&pos,&l,&h),L[pos]=l,H[pos]=h,pipe[pos]=true;
    for(int i=1;i<=m;i++) f[0][i]=0;
}
void dp(){
    for(int i=1;i<=n;i++) {
        for(int h=X[i]+1;h<=m+X[i];h++)
          f[i][h]=min(f[i-1][h-X[i]],f[i][h-X[i]])+1;//刷表
        for(int h=m+1;h<=m+X[i];h++)//处理高度超过m的情况
          f[i][m]=min(f[i][m],f[i][h]);
        for(int h=1;h<=m-Y[i];h++)//处理不按屏幕的情况
          f[i][h]=min(f[i-1][h+Y[i]],f[i][h]);
        for(int h=1;h<=L[i];h++) f[i][h]=inf;//有水管的地方不能达到,所以inf
        for(int h=H[i];h<=m;h++) f[i][h]=inf;
    }
    int ans=inf;
    for(int i=1;i<=m;i++) ans=min(ans,f[n][i]);
    if(ans<inf) {printf("1\n%d\n",ans);return;}
    ans=0;
    for(int i=n;i>=0;i--){
        for(int h=L[i]+1;h<=H[i]-1;h++) if(f[i][h]<inf){
            printf("0\n%d\n",k-ans);
            return;
        }
        if(pipe[i]) ans++;
    }
}
int main(){
    ready();
    dp();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Hi_KER/article/details/82529104