2017.10.4离线赛总结

本文解析了三道算法竞赛题目,包括扩展版石头剪刀布的游戏逻辑实现、无向图中特定条件下的最大权值计算以及简化版小鸟飞行游戏的动态规划解决方案。

第1题:生活大爆炸版石头剪刀布
题意:规则在石头剪刀布的基础上增加斯波克和蜥蜴人,总而言之,每种属性多了一个克星。

思路:(强模拟)

但我还是做的太慢了(花了30分钟)。

第2题:联合权值
题意:无向连通图G有n个点,n-1条边,每个点上有权值w,每条边长度均为1。若 两点的距离为2,则它们之间会产生Wi*Wj的联合权值。
求最大的联合权值及联合全值之和。其和对10007取余。

思路:很简单,找两个点的中间那个点即可,sum维护中间点到其它点的权值之和。计算时就减去该点即可。

第3题:飞扬的小鸟
题意: 就是点击屏幕穿过水管的小鸟。简单化,n*m的平面,有k个水管,每个水管有3个属性,x,L,H。还有处在X=i时,up一次增加的高度UPi和down一次下降的高度DOWNi。(在同一单位时间内可点击多次)。

思路:这真是教课书版的dp(小c),然而dp还是没有时间debug(我也不知道是为什么…)。当然,此dp可以在完全背包的基础上,优化成滚动dp。(也很明显,这一列只与上一列有关)。

#include<bits/stdc++.h>
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define LL long long
#define INF 0x3f3f3f3f
#define N 10005
#define M 1005 
using namespace std;
int n,m,k,a,b,c; 
int up[N],down[N],Sum[N];
struct node{
    int L,H; 
}W[N];
bool mark[N];
int dp[N][M];
void chk(int &x,int y){if(x==-1||x>y)x=y;}
struct P1{
    void solve(){
        REP(i,0,m)dp[0][i]=0;
        int cur=1,Cnt=0;
        REP(i,1,n){
            memset(Sum,-1,sizeof(Sum));
            memset(dp[cur],-1,sizeof(dp[cur]));
            REP(j,W[i].L+1,W[i].H-1){
                int y=j+down[i];
                if(y>m)continue;
                if(dp[!cur][y]!=-1)Sum[j]=dp[!cur][y];
            }
            REP(j,0,m){  
                int y=j+up[i];
                if(y>m)y=m;
                if(dp[!cur][j]!=-1)chk(dp[cur][y],dp[!cur][j]+1);
                if(dp[cur][j]!=-1)chk(dp[cur][y],dp[cur][j]+1);
            }
            REP(j,0,m)if(Sum[j]!=-1)chk(dp[cur][j],Sum[j]);
            REP(j,0,W[i].L)dp[cur][j]=-1;
            REP(j,W[i].H,m)dp[cur][j]=-1;
            bool f=0;
            REP(j,W[i].L+1,W[i].H-1)if(dp[cur][j]!=-1)f=1;
            cur^=1;
            if(!f){
                printf("0\n%d\n",Cnt);
                exit(0); 
            }
            if(mark[i])Cnt++;
        }
        int ans=1e9;
        REP(j,W[n].L+1,W[n].H-1)if(ans>dp[!cur][j]&&dp[!cur][j]!=-1)ans=dp[!cur][j];
        printf("1\n%d\n",ans);
    }
}p1;
struct P2{
    void solve(){
        int Cnt=0;
        memset(dp,-1,sizeof(dp));
        REP(i,1,m)dp[0][i]=0;
        REP(i,1,n){
            memset(Sum,-1,sizeof(Sum));
            REP(j,W[i].L+1,W[i].H-1){
                int y=j+down[i];
                if(y>m)continue;
                if(dp[i-1][y]!=-1){
                    Sum[j]=dp[i-1][y];
                }
            }
            REP(j,1,m){  
                int y=j+up[i];
                if(y>m)y=m;
                if(dp[i-1][j]!=-1)chk(dp[i][y],dp[i-1][j]+1);
                if(dp[i][j]!=-1)chk(dp[i][y],dp[i][j]+1);
            }
            REP(j,1,m)if(Sum[j]!=-1)chk(dp[i][j],Sum[j]);
            REP(j,1,W[i].L)dp[i][j]=-1;
            REP(j,W[i].H,m)dp[i][j]=-1;
            bool f=0;
            REP(j,W[i].L+1,W[i].H-1)if(dp[i][j]!=-1)f=1;
            if(!f){
                printf("0\n%d\n",Cnt);
                exit(0);
            }
            if(mark[i])Cnt++;
        }
        int ans=1e9;
        REP(j,W[n].L+1,W[n].H-1){
            if(ans>dp[n][j]&&dp[n][j]!=-1)ans=dp[n][j]; 
        } 
        printf("1\n%d\n",ans);
    }
}p2;
int main(){
    srand(time(NULL));
    scanf("%d%d%d",&n,&m,&k);
    REP(i,1,n)scanf("%d%d",&up[i],&down[i]);
    REP(i,1,n)W[i]=(node){0,m+1};
    REP(i,1,k){
        scanf("%d%d%d",&a,&b,&c);
        mark[a]=1; 
        W[a]=(node){b,c};
    }
    int x=rand()%2;
    if(x)p1.solve();
    else p2.solve();
    return 0;
}

小结:
感觉每次的考试是看似简单,实则连暴力分都没拿到(以后还是先切分),甚至直接爆0。所以还是先打完暴力就对拍,不急去想正解,稳拿到暴力分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值