ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[SHOI2012] 火柴游戏

2019-06-27 10:48:10  阅读:254  来源: 互联网

标签:10 游戏 删除 int 添加 SHOI2012 火柴 操作 dp


[SHOI2012] 火柴游戏

[题目链接]

链接

[思路要点]

首先发现移动火柴操作可以放到最后做。每一次移动火柴一定可以看做是添加一根火柴再删除一根火柴,并且可以将任意一次添加和一次删除操作合并为一次移动操作,那么可以考虑只使用添加和删除操作,最后再计算出当前情况下使用几次移动操作最优。

然而发现并不清楚优先选择添加还是删除,但是我们知道当添加操作次数相同时,删除操作越少越优,所以可以 \(\text{dp}\),用状态 \(f[i][j]\) 表示当前考虑了前 \(i\) 个数字,当前的添加操作数量为 \(j\) 时的最少删除操作次数。

得到这个之后,对于每一对添加操作数量和删除操作数量,可以三分出移动操作数量或者直接枚举取最优解。

[代码]

#include<stdio.h>
#include<cmath>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=205;
const int inf=0x7f7f7f7f7f;
int dp[maxn][505],p[5],q[5],n,ad[10][10],de[10][10];
int num[10][8]={{0,1,1,1,0,1,1,1},{0,0,0,1,0,0,1,0},{0,1,0,1,1,1,0,1},{0,1,0,1,1,0,1,1},{0,0,1,1,1,0,1,0},{0,1,1,0,1,0,1,1},{0,1,1,0,1,1,1,1},{0,1,0,1,0,0,1,0},{0,1,1,1,1,1,1,1},{0,1,1,1,1,0,1,1}};
char a[maxn],b[maxn];
int as(int s,int f)
{
    int i,ans=0;
    for(i=1;i<=7;i++)
    if(num[s][i]==num[f][i])continue;
    else if(num[s][i]==0) ans++;
    return ans;
}
int ds(int s,int f)
{
    int i,ans=0;
    for(i=1;i<=7;i++)
    if(num[s][i]==num[f][i])continue;
    else if(num[s][i]==1) ans++;
    return ans;
}
int getans(int i,int j)
{
    int ans=inf,k,l=0,maxk=min(i,j);
    for(k=0;k<=maxk;k++)
    {
        ans=min(ans,p[1]*(1+i-k)*(i-k)/2+(i-k)*q[1]+
        p[2]*(1+j-k)*(j-k)/2+(j-k)*q[2]+
        p[3]*(1+k)*k/2+k*q[3]);
    }
    return ans;
}

int main()
{
    int i,j,k,m,ans=inf;
    scanf("%d",&n);
    scanf("%s %s",a,b); 
    scanf("%d%d%d%d%d%d",&p[1],&q[1],&p[2],&q[2],&p[3],&q[3]);
    for(i=0;i<10;i++)
    {
        for(j=0;j<10;j++)
        {
            ad[i][j]=as(i,j);
            de[i][j]=ds(i,j);
        }
    }
    for(i=0;i<n;i++)
    {
        a[i]-='0',b[i]-='0';
    }
    for(i=1;i<=n;i++)
        for(j=0;j<505;j++)
            dp[i][j]=inf;
    for(m=1;m<=n;m++)
        for(k=0;k<10;k++)
        {
            int add=ad[a[m-1]][k]+ad[b[m-1]][k];
            int del=de[a[m-1]][k]+de[b[m-1]][k];
            for(i=0;i<505;i++)
                if(i>=add)
                dp[m][i]=min(dp[m][i],dp[m-1][i-add]+del);
        }
    for(i=0;i<505;i++)
        if(dp[n][i]!=inf)
        ans=min(ans,getans(i,dp[n][i]));
    printf("%d",ans);
    return 0;
}

标签:10,游戏,删除,int,添加,SHOI2012,火柴,操作,dp
来源: https://www.cnblogs.com/wawawa8/p/11095680.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有