zoukankan      html  css  js  c++  java
  • NYOJY 491 幸运三角形

    描述

            话说有这么一个图形,只有两种符号组成(‘+’或者‘-’),图形的最上层有n个符号,往下个数依次减一,形成倒置的金字塔形状,除第一层外(第一层为所有可能情况),每层形状都由上层决定,相邻的符号相同,则下层的符号为‘+’,反之,为‘-’;如下图所示(n = 3 时的两种情况):

                                               

    如果图中的两种符号个数相同,那这个三角形就是幸运三角形,如上图中的图(2).

    输入
    有多组测试数据(少于20组)。
    每行含一个整数n(0<n<20)。
    输出
    输出相应的幸运三角形个数。
    样例输入
    3
    4
    
    样例输出
    4
    6
    ///排列组合第一行,然后直接寻找是否相等
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define N 1010
    #define MOD 1000000007
    using namespace std;
    int n,m,ans[25];
    int a[25];///待排列的数存储在此
    bool vis[15];
    int p[N][N],k;
    int sum,num,tot;
    void dfs(int cnt)///按字典序输出n个数选m个数的所有排列
    {
        if(cnt==m)
        {
            for(int i=0; i<m; i++)
            {
                if(ans[i] == ans[i+1] && i+1 < m)
                    p[1][k] = 1,sum++;
                else
                    p[1][k] = 2;
                k++;
                if(ans[i] == 1)
                    sum++;
            }
            int c = 2;
            while(c < m)
            {
                k = 0;
                for(int i = 0; i < m - c + 1; i++)
                {
                    if(p[c-1][i] == p[c-1][i+1] && i+1 < m - c + 1)
                        p[c][k] = 1,sum++;
                    else
                        p[c][k] = 2;
                    k++;
                }
                c++;
            }
            if(sum == num)
                tot++;
            k = 0;
    //        for(int i=0; i<m; i++)
    //            cout<<ans[i]<<"***";
    //        cout<<endl;
    //        for(int i = 1; i < m; i++)
    //        {
    //            for(int j = 0 ; j < m-i; j++)
    //                cout<<p[i][j]<<"***";
    //            cout<<endl;
    //        }
    //        cout<<sum<<" "<<num<<endl;
            sum = 0;
            return ;
        }
        for(int i=0; i<n; i++)
        {
            ans[cnt]=a[i];
            dfs(cnt+1);
        }
    }
    int main()
    {
        while(cin>>m)
        {
            k = 0;
            n = 2;
            sum = 0;
            tot = 0;
            num = m * (m + 1);
            if(num % 4)
            {
                cout<<0<<endl;
                continue;
            }
            else
                num /= 4;
            fill(vis,vis+25,0);
            a[0] = 1;
            a[1] = 2;
            dfs(0);
            cout<<tot<<endl;
        }
        return 0;
    }
    TLE

    纯粹dfs,回溯还未入门,不过如果应试的话完全可以打表,毕竟数据量不是太大。

    ///排列组合第一行,然后直接寻找是否相等
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define N 1010
    #define MOD 1000000007
    using namespace std;
    int n,m,ans[25];
    int a[25];///待排列的数存储在此
    bool vis[15];
    int p[N][N],k;
    int sum,num,tot;
    void dfs(int cnt)///按字典序输出n个数选m个数的所有排列
    {
        if(cnt==m)
        {
            for(int i=0; i<m; i++)
            {
                if(ans[i] == ans[i+1] && i+1 < m)
                    p[1][k] = 1,sum++;
                else
                    p[1][k] = 2;
                k++;
                if(ans[i] == 1)
                    sum++;
            }
            int c = 2;
            while(c < m)
            {
                k = 0;
                for(int i = 0; i < m - c + 1; i++)
                {
                    if(p[c-1][i] == p[c-1][i+1] && i+1 < m - c + 1)
                        p[c][k] = 1,sum++;
                    else
                        p[c][k] = 2;
                    k++;
                }
                c++;
            }
            if(sum == num)
                tot++;
            k = 0;
    //        for(int i=0; i<m; i++)
    //            cout<<ans[i]<<"***";
    //        cout<<endl;
    //        for(int i = 1; i < m; i++)
    //        {
    //            for(int j = 0 ; j < m-i; j++)
    //                cout<<p[i][j]<<"***";
    //            cout<<endl;
    //        }
    //        cout<<sum<<" "<<num<<endl;
            sum = 0;
            return ;
        }
        for(int i=0; i<n; i++)
        {
            ans[cnt]=a[i];
            dfs(cnt+1);
        }
    }
    int main()
    {
        for(m = 1; m < 21; m++)
            //while(cin>>m)
        {
            k = 0;
            n = 2;
            sum = 0;
            tot = 0;
            num = m * (m + 1);
            if(num % 4)
            {
                cout<<0<<",";
                continue;
            }
            else
                num /= 4;
            fill(vis,vis+25,0);
            a[0] = 1;
            a[1] = 2;
            dfs(0);
            cout<<tot<<",";
        }
        return 0;
    }
    打表过了

    回溯才是正解,可以减掉重复计算的值,但是自己没搞懂,留下正解先

    ///边回溯边计算,避免重复计算
    #include"iostream"
    #include<cstring>
    #include<stdio.h>
    #include<time.h>
    using namespace std;
    typedef unsigned char uchar;
    
    //char cc[2]={'+','-'};    //便于输出
    int n,                     //第一行符号总数
        half,                 //全部符号总数一半
        counter;             //1计数,即  '-' 号计数
        
    char **p;                //符号存储空间    
    long sum;                //符合条件的三角形计数
    
    //t,第一行第 t个符号
    void Backtrace(int t)
    {
        int i, j;
        
        if( t > n )
            sum++;
        else
        {
           for(i=0; i<2; ++i)  //只取  0('+')  或者  1('-')
           {
                p[1][t] = i;   //第一行第 t个符号
                counter += i;        //'-'号统计
                for(j=2; j<=t; ++j)    //当第一行符号 >=2时,可以运算出下面行的某些符号(第一行有几个数就可以相应往下计算几行,每次计算过的就不用重复计算) 
                {
                    p[j][t-j+1] = p[j-1][t-j+1]^p[j-1][t-j+2];//通过异或运算下行符号
                    counter += p[j][t-j+1];                        
                }
                if( (counter <= half) && ( t*(t+1)/2 - counter <= half) )//若符号统计未超过半数,并且另一种符号也未超过半数
                    Backtrace(t+1);            //在第一行增加下一个符号    
                //回溯,判断另一种符号情况
                for(j=2; j<=t; ++j)    
                    counter -= p[j][t-j+1];         
                counter -= i;
           }
        }
    }
    
    int main()
    {  
        while(scanf("%d", &n) != EOF)
        {
            counter = 0;
            sum = 0;
            half = n*(n+1)/2;
            
            if( half%2 == 0 )//总数须为偶数,若为奇数则无解
            {
                half /= 2;
                p = new char *[n+1];
                for(int i=0; i<=n; ++i)
                {
                   p[i] = new char[n+1];
                   memset(p[i], 0, sizeof(char)*(n+1));
                }   
                Backtrace(1);
            }    
            printf("%d
    ", sum);
        }
        return 0;
    }
    回溯正解

    http://www.cnblogs.com/dongsheng/archive/2013/06/16/3138607.html

  • 相关阅读:
    删除datatable的重复行
    导出大Excel
    winform调用plugin
    System.AppDomain.CurrentDomain.BaseDirectory总是取得根目录
    能不能多想一点呢?
    执行语句使用exec (sql)
    open the folder
    取得一个表的所有字段
    快讯:麦考林第四季度净利110万美元同比减62%
    麦考林第四季度净利110万美元同比减62%(图解)
  • 原文地址:https://www.cnblogs.com/ACMERY/p/5278131.html
Copyright © 2011-2022 走看看