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 ;
}
posted @ 2012-08-20 11:09  Misty_1  阅读(148)  评论(0编辑  收藏  举报