NOIP2011(DAY1)解题报告(C/C++)(铺地毯)(选择客栈)(Mayan 游戏)

来源:互联网 发布:部落冲突男王数据 编辑:程序博客网 时间:2024/05/16 17:33

2017.3.11的校内赛

毛主席教导我们:“与人斗,其乐无穷!”

在考完了10年前的几套题(也就是1D4T的格式)过后,再回来做我们目前的2D6T的题。虽然说题变少了(时间没有变),但是也有些有趣的地方。

1.铺地毯


解题报告:
这道题我们只需要巧妙地将两个点读入,再从后往前循环,输出即可:

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int N=10005;int n;int x,y;int x1[N],y1[N],x2[N],y2[N];int main(){    freopen("carpet.in","r",stdin);    freopen("carpet.out","w",stdout);    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        int a,b,g,k;        scanf("%d%d%d%d",&a,&b,&g,&k);        x1[i]=a,y1[i]=b,x2[i]=a+g,y2[i]=b+k;    }    scanf("%d%d",&x,&y);    for(int i=n;i>=1;i--)    if(x1[i]<=x&&x2[i]>=x&&y1[i]<=y&&y2[i]>=y)    {        printf("%d",i);        return 0;    }    printf("-1");    return 0;}

2.选择客栈


解题报告:
这道题我原本是想搞一个前缀和,记录每一个点前面的符合要求的咖啡馆的个数,过后再两两枚举,判断他们的前缀和之差是否大于零。结果最后编的代码只过了一个点。
下面吗我们来讲讲正解:
正解的思路是先求出所有可能的情况,再减去这其中不满足要求的情况,得到的就是所求结果。
而我们对情况的求法就是将其当做组合数来做,拿一个数组不断累加,需要是清零就可以了。

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int N=2000005;const int K=55;int n,k,p;int sum1=0,sum2=0;int col[N],flag[N]={0},ans[K]={0};int main(){    freopen("hotel.in","r",stdin);    freopen("hotel.out","w",stdout);    scanf("%d%d%d",&n,&k,&p);    for(int i=1;i<=n;i++)    {        int b;        scanf("%d%d",&col[i],&b);        if(b<=p)flag[i]=1;    }    for(int i=1;i<=n;i++)//求不满足的情况     {        if(flag[i])//要找出一段连续的flag!=1的数,以此为累加器的清零标准         {            memset(ans,0,sizeof(ans));            continue;        }        sum1+=ans[col[i]];        ans[col[i]]++;    }    memset(ans,0,sizeof(ans));    for(int i=1;i<=n;i++)//求所有可能的情况     {        sum2+=ans[col[i]];        ans[col[i]]++;    }    printf("%d\n",sum2-sum1);    return 0;}

3.Mayan 游戏


解题报告:
这道题看似比较复杂:需要考虑的情况多,可能有横向把方块消掉,也可以是纵向,还可以是横向竖向一起消掉。此外,还要考虑左移还是右翼,是否为空等等。
但是这道题实质上就是一个搜索题(我校的大神将其称为“大暴力”),只不过纯粹的搜索只有30%的分,要的满分的话需要这几个优化:
1.记录每个颜色的方块,如果已经少于了三,就不必继续搜索(剪枝);
2.如果是两个相同颜色的方块,他们不论是移动哪个(往对方的方向)都一样,所以不用考虑(剪枝);
3.在互换位置时可以把向左移等效为另一个方块向右移;

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int N=10;const int M=6;const int T=3;int cnt[N+5],color[N][N],n,lin[M][T];bool remove(int temp[][10])//消除方块的函数 {    bool pos[10][10]={0} ,flag=0;    for(int i=1;i<=5;++i)//打出pos数组     for(int j=1;j<=7;++j)    if(temp[i][j])    {        if(i<=3&&temp[i][j]==temp[i+1][j]&&temp[i+1][j]==temp[i+2][j])        pos[i][j]=pos[i+1][j]=pos[i+2][j]=1;        if(j<=5&&temp[i][j]==temp[i][j+1]&&temp[i][j+1]==temp[i][j+2])        pos[i][j]=pos[i][j+1]=pos[i][j+2]=1;    }    for(int i=1;i<=5;++i)//消除     for(int j=1;j<=7;++j)    if(pos[i][j])    temp[i][j]=0,flag=1 ;    return flag;//无可消除时返回 }void falldown(int temp[][10])//特判,处理掉落的情况 {    int k ,tmp ;    for(int i=1;i<=5;++i)    {        k=0;        for(int j=1;j<=7;++j)        {            tmp=temp[i][j] ,temp[i][j]=0 ;            if(tmp)temp[i][++k]=tmp;        }    }}bool check(int temp[][10])//是否还有方块存在 {    for(int i=1;i<=5;++i)    for(int j=1;j<=7;++j)        if(temp[i][j])return 0;    return 1;}void dfs(int code,int temp[][10])//搜索的主题 {    if(code>n)    {        if(check(temp))        {            for(int i=1;i<=n;++i)//输出走法             {                if(lin[i][2])printf("%d %d -1\n",lin[i][0],lin[i][1]-1);                else printf("%d %d 1\n",lin[i][0]-1,lin[i][1]-1);            }            exit(0);        }        return;    }    int tmp[10][10]={0};    memset(cnt,0,sizeof cnt);    for(int i=1;i<=5;++i)    for(int j=1;j<=7;++j)    ++cnt[temp[i][j]];    for(int i=1;i<=10;++i)//如果还有少于等于2的个数就剪枝     if(cnt[i]==1||cnt[i]==2)    return;    for(int i=1;i<5;++i)    for(int j=1;j<=7;++j)    if(temp[i][j]!=temp[i+1][j])    {        memcpy(tmp,temp,sizeof tmp);//数组赋值,相当于将temp的数据拷贝到tmp中         lin[code][0]=i,lin[code][1]=j,lin[code][2]=!temp[i][j];        swap(tmp[i][j],tmp[i+1][j]);//右边有数就交换         falldown(tmp);//右边没数就掉落         while(remove(tmp))            falldown(tmp);//清除完后可能的掉落         dfs(code+1,tmp);//下一步继续搜索     }}int main(){    scanf("%d",&n);    for(int i=1;i<=5;++i)    for(int j=1;;++j)    {        scanf("%d",&color[i][j]);        if(!color[i][j])break;//遇到0就退出     }    dfs(1,color);    printf("-1");    return 0;}

以上
2017.3.15

0 0