zoukankan      html  css  js  c++  java
  • Noip2015 提高组 Day1

    T1神奇的幻方

    直通

    思路:

      制定一个lrow记录上一个数字所在的行数,lcolume记录上一个数字所在的列数,然后根据题目的描述进行更改即可

    上代码:

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    const int Maxn = 40;
    int n,a[Maxn][Maxn];
    
    int main() {
        scanf("%d",&n);
        int mid=n/2+1,Max=n*n;
        int lrow=1,lcolume=mid;
        a[lrow][lcolume]=1;
        for(int i=2; i<=Max; ++i) {
            if(lrow==1 && lcolume!=n)
                lrow=n,a[lrow][++lcolume]=i;
            else if(lrow!=1 && lcolume==n)
                lcolume=1,a[--lrow][lcolume]=i;
            else if(lrow==1 && lcolume==n)
                a[++lrow][lcolume]=i;
            else if(lrow!=1 && lcolume!=n) {
                if(a[lrow-1][lcolume+1]==0)
                    a[--lrow][++lcolume]=i;
                else
                    a[++lrow][lcolume]=i;
            }
        }
        for(int i=1; i<=n; ++i) {
            for(int j=1; j<=n; ++j)
                printf("%d ",a[i][j]);
            printf("
    ");
        }
        return 0;
    } 

    T2 信息传递

    直通

    思路:

      讲真这道题是有各种各样的作法...这里给出的是拓扑排序+dfs

    上代码:

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    const int M = 2e5 + 1; 
    int n,minn=0x7fffffff;
    int t[M],ru[M];
    bool v[M];
    
    void topo(int i)
    {
        int v=t[i];
        t[i]=0;
        ru[v]--;
        if(!ru[v]) topo(v);
    }
    
    void dfs(int x,int steps)
    {
        if(v[x])///环完成 
        {
            if(steps<minn) minn=steps;///更新 
            return;
        }
        v[x]=true;
        dfs(t[x],steps+1);
        return;
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&t[i]);
            ru[t[i]]++;
        }
        for(int i=1;i<=n;i++)
            if(!ru[i]) topo(i);
        for(int i=1;i<=n;i++)
            if(ru[i] && !v[i]) dfs(i,0);
        printf("%d",minn);
        return 0;
    }

    T3 斗地主

    直通

    数据保证:所有的手牌都是随机生成的。

    思路:

      首先说在前面,这题有好几种解法....

      什么bfs啊,什么dfs+贪心啊,什么dp啊.

      然而我只会dfs+贪心以及dp版的,但是由于懒嘛,就只写dp版的啦~

      具体完整版请出门右拐通往gaoji大佬的博客园:www.cnblogs.com/zwfymqz/

      搜索斗地主:你会看到你想要的

    坑点:

      如上大红字,这就是为什么贪心差不多可以过的原因了吧~

        在做题的时候一定要将循环里的变量搞清楚!这次吃了大亏了...qwq

    上代码:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    
    using namespace std;
    
    const int M = 24;
    int T,n,ans;
    ///手牌的组数,每组手牌的张数,记录的答案 
    int dp[M][M][M][M];
    ///dp[i][j][k][l]表示打出i套四张,j套三张,k套两张,l张单牌所需要的最少步数
    int cnum[M],happens[M/4];
    int num[4]={0,5,3,2};
    
    int calc(int one,int two,int three,int four,int king) 
    {
        if(king==1)///只出现一张大小王
        {
            one++; ///当作一张单牌
            king--; ///清空 
        }
        if(king==0) ///当做一张单牌来用 
             return dp[four][three][two][one];
        else 
            //return min(dp[four][three][two][one+2],dp[four][three][two+1][one]); 
            return min(dp[four][three][two][one+2],dp[four][three][two][one]+1);
            ///当做2张单牌,或者当做一对对牌 
    }
    
    void dfs(int now) ///now是指已经操作的次数 
    {
        if(now>=ans) ///最优性剪枝,这个重要 
            return;
        memset(happens,0,sizeof(happens));///清空 
        for(int i=2;i<=14;i++)
            happens[cnum[i]]++; ///记录出现几次的牌有几种 
        ans=min(ans,now+calc(happens[1],happens[2],happens[3],happens[4],cnum[0]));
        for(int k=1;k<=3;k++) ///k表示几顺子
        {
            for(int i=3;i<=14;i++)
            {
                int j;
                for(j=i;j<=14 && cnum[j]>=k;j++)///若可能组成k顺子
                {
                    cnum[j]-=k; ///耗费掉了
                    if(j-i+1>=num[k]) 
                        dfs(now+1); ///组成k顺子成功!!! 
                 } 
                 for(j--;j>=i;j--)
                     cnum[j]+=k; ///回溯 
            }
        }
    }
    
    int main()
    {
        scanf("%d%d",&T,&n);
        memset(dp,1,sizeof(dp));
        ///上面那个其实没什么用...可有可无 
        dp[0][0][0][0]=0;
        ///当每张都不打出去的时候,步数为0 
        for(int i=0;i<=n;i++) ///four 
            for(int j=0;j<=n;j++) ///three 
                for(int k=0;k<=n;k++) ///two 
                    for(int l=0;l<=n;l++) ///one 
                        if(i*4+j*3+k*2+l<=n) ///在范围之内
                        {
                            ///赋值为最坏情况:当每张牌都一张一张的打出去
                            ///故将dp数组memset大概是没什么用的 
                            dp[i][j][k][l]=i+j+k+l;
                            if(i)
                            {
                                ///将4张牌进行分解
                                ///(3+1) || (2+2) 
                                dp[i][j][k][l]=min(dp[i][j][k][l],min(dp[i-1][j+1][k][l+1],dp[i-1][j][k+2][l]));
                                ///(2+1+1) || (1+1+1+1) 
                                dp[i][j][k][l]=min(dp[i][j][k][l],min(dp[i-1][j][k+1][l+2],dp[i-1][j][k][l+4]));
                                if(k>=2)
                                    dp[i][j][k][l]=min(dp[i][j][k][l],dp[i-1][j][k-2][l]+1),
                                    dp[i][j][k][l]=min(dp[i][j][k][l],dp[i-1][j][k-1][l]+1);
                                ///四带一对对牌(一个对牌) 
                                if(l>=2)
                                    dp[i][j][k][l]=min(dp[i][j][k][l],dp[i-1][j][k][l-2]+1);
                                ///四带一对单牌(2张单牌) 
                                dp[i][j][k][l]=min(dp[i][j][k][l],dp[i-1][j][k][l]+1);
                                ///什么都不带
                            }
                            if(j)
                            {
                                ///将3张牌进行分解 
                                ///(2+1) || (1+1+1)
                                dp[i][j][k][l]=min(dp[i][j][k][l],min(dp[i][j-1][k+1][l+1],dp[i][j-1][k][l+3]));
                                if(k)
                                    dp[i][j][k][l]=min(dp[i][j][k][l],dp[i][j-1][k-1][l]+1);
                                ///三带一对 
                                if(l)
                                    dp[i][j][k][l]=min(dp[i][j][k][l],dp[i][j-1][k][l-1]+1);
                                ///三带一 
                                dp[i][j][k][l]=min(dp[i][j][k][l],dp[i][j-1][k][l]+1);
                                ///什么都不带 
                            }
                            if(k)
                            {
                                ///将2张牌进行分解 
                                dp[i][j][k][l]=min(dp[i][j][k][l],dp[i][j][k-1][l+2]);
                                ///一对牌 
                                dp[i][j][k][l]=min(dp[i][j][k][l],dp[i][j][k-1][l]+1); 
                            }
                            if(l)///一张单牌 
                                dp[i][j][k][l]=min(dp[i][j][k][l],dp[i][j][k][l-1]+1);
                        }
        while(T--)
        {
            memset(cnum,0,sizeof(cnum));
            ///多组数据 
            ans=n;
            ///最差情况
            int ai,meiyong;
            for(int i=1;i<=n;i++)
            { ///读入数码,以及花色(讲真没啥用) 
                scanf("%d%d",&ai,&meiyong);
                if(ai==1)
                    cnum[14]++;
                ///储存A(尖?),把A转化为14数码 
                else
                cnum[ai]++;
                ///其他的按原来数码进行储存(大小王也一样~) 
            }
            dfs(0);
            printf("%d
    ",ans);
        }
        return 0;
    }

    如果运气好也是错,那我倒愿意错上加错!

    ❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀

  • 相关阅读:
    在CentOS7上部署OpenStack 步骤详解
    Linux运维工程师工作手册
    Nginx+Keepalived实现Web服务器负载均衡
    Django Nginx+uwsgi 安装配置
    Docker-搭建Docker Registry
    centos7系统默认防火墙Firewall使用方法
    Shell脚本编写及常见面试题(二)
    Shell脚本编写及常见面试题(一)
    Linux之解决每次git pull/git push都需输入密码设置
    基于thinkphp5的Excel上传
  • 原文地址:https://www.cnblogs.com/zxqxwnngztxx/p/7107085.html
Copyright © 2011-2022 走看看