• poj 2947 Widget Factory(高斯消元)


    题意:p strat  end ,表示员工i开始工作的星期,以及被解雇的星期,和在这期间他共加工了p种首饰,下一行是他都加工了哪几种首饰,问你通过这些记录是否能得出加工每种首饰需要多少天。

    思路:典型的高斯消元,设每种首饰需要的天数为xi,这个的每个记录就是一个方程,所以用高斯消元法解这个方程组就可以了,需要注意的是,他给出的是一个星期中的某一天,但他做了几个星期不知道,a1*x1 + a2 * x2 + .....=( b + 7 * x ) % 7 ;在本题中要注意%7 ,嗯,每个地方都要摸,不能超出7。

    代码:

    View Code
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <math.h>
    #define  N 305
    using namespace std ;
    
    int val[N][N] , d[N] ;
    int n , m ;
    //转化日期
    int chang ( char str[] )
    {
        if ( strcmp ( str , "MON" ) == 0 )
        return 1 ;
        else if ( strcmp ( str , "TUE" ) == 0 )
        return 2 ;
        else if ( strcmp ( str , "WED" ) == 0 )
        return 3 ;
        else if ( strcmp ( str , "THU" ) == 0 )
        return 4 ;
        else if ( strcmp ( str , "FRI" ) == 0 )
        return 5 ;
        else if ( strcmp ( str , "SAT" ) == 0 )
        return 6 ;
        else
        return 7 ;
    }
    //高斯消元
    void solve()
    {
        int row , col , i , j , k , t , tem ;
    
        for ( row = 0 , col = 0 ; row < m && col < n ; col++ )
        {
            //寻找交换行
            for ( i = row ; i < m ; i++ )
            if ( val[i][col] )
            break ;
            
            if ( val[i][col] )
            {
                //交换两行
                for ( j = col ; j <= n ; j++ )
                {
                    tem = val[i][j] ;
                    val[i][j] = val[row][j] ;
                    val[row][j] = tem ;
                }
                //用每一行与这一行做减法
                for ( j = 0 ; j < m ; j++ )
                if ( j != row && val[j][col] )
                {
                    int ta = val[j][col] ;
                    int tb = val[row][col] ;
                    for ( k = 0 ; k <= n ; k++ )
                    val[j][k] = (( val[j][k] * tb - val[row][k] * ta ) % 7 + 7 ) % 7 ;
                }
                row++ ;
            }
        }
        
        //无解
        for ( i = row ; i < m ; i++ )
        if ( val[i][n] != 0 )
        {
            printf ( "Inconsistent data.\n" );
            return ;
        }
        
        //无穷解
        if ( row < n )
        {
            printf ( "Multiple solutions.\n" );
            return ;
        }
        
        //唯一解
        for ( i = n - 1 ; i >= 0 ; i-- )
        {
            tem = val[i][n] ;
            for ( j = i + 1 ; j < n ; j++ )
            tem = ( ( tem - val[i][j] * d[j] ) %7  + 7 ) % 7 ;
            while ( tem % val[i][i] != 0 )
            tem += 7 ;
            d[i] = ( tem / val[i][i] ) % 7 ;
        }
        
        //每种首饰的加工时间在3-9天
        for ( i = 0 ; i < n ; i++)
        if ( d[i] < 3 )
        d[i] += 7 ;
    
        for ( i = 0 ; i < n ; i++ )
        {
            if ( i )
            printf ( " %d" , d[i] );
            else
            printf ( "%d" , d[i] );
        }
        printf ( "\n" );
        return ;
    }
    
    int main()
    {
        int i , j , x , dx , date ;
        char s[10] , t[10] ;
    
        while ( scanf ( "%d%d" , &n , &m ) != EOF )
        {
            if ( !( n + m ))
            break;
    
            memset( val , 0 , sizeof ( val ));
            memset( d , 0 , sizeof ( d ));
            for ( i = 0 ; i < m ; i++ )
            {
                //getchar();
                scanf ( "%d %s %s" , &x , s , t );
                date = ( chang( t ) - chang( s ) + 1 + 7 ) % 7 ;
                val[i][n] = date ;
                for ( j = 0 ; j < x ; j++ )
                {
                    scanf ( "%d" , &dx );
                    val[i][dx-1]++ ;
                }
                for( j = 0 ; j < n ; j++ )
                val[i][j] %= 7 ;
            }
    
            solve( ) ;
        }
        return 0 ;
    }

    还想说一下高斯消元,其实就是利用矩阵求线性方程的解,这个在线性代数中有讲到,我也是又翻了下课本才想起来的。下面给出一个模板,每一步都讲得很详细。

    代码:

    View Code
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <math.h>
    #define  N 1002
    using namespace std ;
    
    int data[N][N] , vis[N] , x[N] ;
    int n , m ;
    
    void print()
    {
        int i , j ;
        for ( i = 0 ; i < n ; i++ )
        {
            for ( j = 0 ; j < m + 1 ; j++ )
            {
                if ( j )
                printf ( " %d" , data[i][j] );
                else
                printf ( "%d" , data[i][j] );
            }
            printf ( "\n" );
        }
        printf ( "\n" );
    }
    
    int gcd ( int x , int y )
    {
        if ( !y )
        return x ;
        else
        return gcd ( y , x % y );
    }
    
    int lcm ( int x , int y )
    {
        return x * y / gcd ( x , y ) ;
    }
    
    //-2表示有浮点数解,但无整数解,-1表示无解,0表示唯一解,
    //大于0表示无穷解,并返回自由变元的个数
    int Gauss ( )
    {
        int col ,   row , i , j , k , tem , tmax ; // tmax表示当前这列绝对值最大的行.
        //row 当前处理的行,
        
        for ( col = 0 , row = 0 ; row < n && col < m ; col++ , row++ )
        {
            tmax = row ;//寻找当前列中绝对值最大的那行与之交换,为了在除法时减小误差
            for( i = row + 1 ; i < n ; i++ )
            if ( abs ( data[i][col] ) > abs ( data[tmax][col] ))
            tmax = i ;
            //cout<<data[tmax][col]<<endl;
            //交换两行元素
            if ( tmax != row )
            {
                for ( j = row ; j < m + 1 ; j++ )
                {
                    tem = data[tmax][j] ;
                    data[tmax][j] = data[row][j] ;
                    data[row][j] = tem ;
                }
            }
            //说明该col列第row行以下全是0了,则处理当前行的下一列.
            if ( data[row][col] == 0 )
            {
                row-- ;
                continue ;
            }
            
            //每一行都与当前行进行减法运算,使得与它相减的当前列的元素为0 
            for ( i = row + 1 ; i < n ; i++ )
            if ( data[i][col] )
            {
                //寻找最小公倍数
                int tx = lcm ( abs( data[i][col] ) , abs( data[row][col] )) ;
                int ta = tx / abs( data[i][col] ) ;
                int tb = tx / abs( data[row][col] ) ;
                if ( data[i][col] * data[row][col] < 0 )
                ta = -ta ;// 异号的情况下是两个数相加.
                for ( j = col ; j < m + 1 ; j++ )
                data[i][j] =  data[i][j] * ta - data[row][j] * tb  ;
            }
            cout<<endl;
            print();//打印出每个变化后的矩阵
        }
        
        // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
        for( i = row ; i < n ; i++ )
        if ( data[i][col] != 0 )
        return -1 ;
        
         // 2. 无穷解的情况: 在m * ( m + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
        // 且出现的行数即为自由变元的个数.
        if ( row < m )
        {
             // 首先,自由变元有 m - row 个,即不确定的变元至少有var - k个
             // 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第row行到第n行.
            // 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的.
            for ( i = row - 1 ; i >= 0 ; i-- )
            {
                int num = 0 ; // 用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元.
                int pos ;
                for ( j = 0 ; j < m + 1 ; j++ )
                if ( data[i][j] && !vis[j] )
                {
                    num++ ;pos = j ;
                }
                if ( num > 1 )
                continue ;
                
                // 说明就只有一个不确定的变元pos,那么可以求解出该变元,且该变元是确定的.
                tem = data[i][m] ;
                for ( j = 0 ; j < m ; j++ )
                if ( data[i][j] && j != pos )
                tem -= data[i][j] * x[j] ;
    
                x[pos] = tem / data[i][pos] ;
                vis[pos] = 1 ;
            }
            return m - i ;
        }
        
         // 3. 唯一解的情况: 在m * ( m + 1)的增广阵中形成严格的上三角阵.
        for ( i = m - 1 ; i >= 0 ; i-- )
        {
            tem = data[i][m] ;
            for ( j = i + 1 ; j < m ; j++  )
            if( data[i][j] )
            tem -= data[i][j] * x[j] ;
    
            if ( tem % data[i][i] )
            return -2 ;//有浮点数解
            x[i] = tem / data[i][i] ;
            vis[i] = 1 ;
        }
        return 0 ;
    }
    
    int main()
    {
        int flag , i , j ;
    
        //freopen("input.txt" , "r" , stdin );
    
        while ( scanf ( "%d%d" , &n , &m ) != EOF )
        {
            memset ( data , 0 , sizeof ( data ));
            memset ( vis , 0 , sizeof ( vis ));
            //输入矩阵元素
            for ( i = 0 ; i < n ; i++ )
            {
                for ( j = 0 ; j < m + 1 ; j++ )
                scanf ( "%d" , &data[i][j] );
            }
            
            flag = Gauss () ;
            if ( flag == -1 )
            {
                printf ( "无解\n" );
            }
            else if ( flag == -2 )
            {
                printf ( "有浮点数解\n" ) ;
            }
            else if ( flag > 0 )
            {
                printf ( "有无穷解\n" ) ;
            }
            else
            {
                for ( i = 0 ; i < m ; i++ )
                {
                   printf ( "x%d = %d\n" , i + 1 , x[i] );
                }
                //printf ( "\n" );
            }
        }
        return 0 ;
    }
  • 相关阅读:
    web版仿微信聊天界面|h5仿微信电脑端案例开发
    h5仿微信聊天(高仿版)、微信聊天表情|对话框|编辑器
    原生wcPop.js消息提示框(移动端)、内含仿微信弹窗效果
    旅行app(游记、攻略、私人定制) | 顺便游旅行H5移动端实例
    【h5+c3】web前端实战项目、快装webapp手机案例源码
    h5区块链项目实战
    css3波纹特效、H5实现动态波浪
    H5移动端项目案例、web手机微商城实战开发
    HTML5仿微信聊天界面、微信朋友圈实例
    Android 给服务器发送网络请求
  • 原文地址:https://www.cnblogs.com/misty1/p/2647238.html
Copyright © 2020-2023  润新知