zoukankan      html  css  js  c++  java
  • hdu4418(概率dp + 高斯消元)

    应该是一个入门级别的题目。

    但是有几个坑点。

    1. 只选择x能到达的点作为guass中的未知数。

    2. m可能大于n,所以在构建方程组时未知数的系数不能直接等于,要+=

    3.题意貌似说的有问题,D为-1的时候,和题目说的不一样.

    //
    //  main.cpp
    //  hdu4418
    //
    //  Created by New_Life on 16/8/9.
    //  Copyright © 2016年 chenhuan001. All rights reserved.
    //
    
    //高斯消元模板:  浮点数
    
    
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #define maxn 210
    #define N 210
    #define CL(a,num) memset((a),(num),sizeof(a))
    #define iabs(x)  ((x) > 0 ? (x) : -(x))
    #define EPS 1e-8
    using namespace std;
    int equ,var;//方程个数和自由元的个数
    double a[maxn][maxn];
    double x[maxn],free_x[maxn];//解集
    
    void Debug()
    {
        int i,j;
        for(i=0;i<equ;i++){
            for(j=0;j<var+1;j++)
                printf("%.2lf ",a[i][j]);
            cout<<endl;
        }
    }
    
    int zero(double x)
    {
        if( iabs(x)<EPS ) return 1;
        return 0;
    }
    int Guass(){
        int i,j,k,col;
        CL(x,0);CL(free_x,1);//清空解集
        
        for(k=0,col=0;k<equ && col<var ;k++,col++){//枚举行和列
            //	cout<<k<<" "<<col<<endl;
            int max_r = k;
            for(i=k+1;i<equ;i++)
                if(iabs(a[i][col]) > iabs(a[max_r][col])) max_r = i;
            if(max_r != k)//交换
                for(i=k;i<var+1;i++)
                    swap(a[k][i],a[max_r][i]);
            
            if( zero(a[k][col]) ) {
                k--; //为什么有k--;模拟下这样可以减的多点
                continue;
            }
            
            for(i=k+1;i<equ;i++){
                if(!zero(a[i][col])){
                    //	int lcm = LCM(a[k][col],a[i][col]);
                    //	int ta = lcm/iabs(a[i][col]);
                    //	int tb = lcm/iabs(a[k][col]);
                    //	如果读入的矩阵是整数可按照上面的写,否则得按照下面的写
                    double tb = iabs(a[i][col])/iabs(a[k][col]);
                    if(a[i][col]*a[k][col]<0) tb=-tb;
                    for(j=col;j<var+1;j++)
                        a[i][j] = a[i][j] - tb*a[k][j];
                }
            }
        }
        //	Debug();
        //1.无解的情况出现(0,0,0,0,……a)这样的行且a!=0
        for(i=k;i<equ;i++){
            if(!zero(a[i][col]))
            {
                printf("Impossible !
    ");
                return -1;
            }
        }
        //2.无穷解的情况,再var*(var+1)的增广矩阵中出现(0,0,0……0)这样的行
        //出现的行数便是自由变元的个数
        if(k<var){
            int num = 0,freeidx=0;
            for(i=k-1;i>=0;i--){
                num=0;
                //用于判断该行的不确定的变元的个数,如果超过1则无法求解
                //它们仍然为不确定的变元
                double tmp = a[i][var];
                for(j=0;j<var;j++)
                    if(!zero(a[i][j]) && free_x[j]){
                        num++;
                        freeidx = j;
                    }
                if(num>1) continue;
                tmp=a[i][var];
                for(j=0;j<var;j++){
                    if(!zero(a[i][j]) && j != freeidx) tmp -= a[i][j]*x[j];
                }
                x[freeidx] = tmp/a[i][freeidx];
                free_x[freeidx]=0;
            }
            if(free_x[0] == 0) printf("%.2lf
    ",x[0]);
            else printf("Impossible !
    ");
            return var-k;
        }
        //3.唯一解的情况
        for(i=k-1;i>=0;i--)
        {
            double tmp=a[i][var]*1.0;
            for(j=i+1;j<var;j++)
                tmp-=a[i][j]*x[j];
            x[i] = tmp/(a[i][i]*1.0);
        }
        printf("%.2lf
    ",x[0]);
        return 0;
    }
    
    double g[N];
    int tg[N];
    int mark[N][2];
    int id = 0;
    int n,m;
    double savevar[N];
    int flagflag;
    
    //感觉这里面可以直接建立方程
    void dfs(int p,int d,int y)
    {
        int td = d;
        mark[p][d] = id++;
        int tp = p;
        a[ mark[p][d] ][ mark[p][d] ] = -1;
        double tmp = 0;
        for(int i=1;i<=m;i++)
        {
            if(d==0) tp++;
            else tp--;
            
            if(tp == 0) d = 0;
            else if(tp==n-1) d=1;
            
            if(tg[i]==0) continue;
            
            tmp += i*g[i];
            
            if(tp==y) {flagflag=1;continue;}
            
            if(mark[tp][d]==-1)
                dfs(tp,d,y);
            
            a[ mark[p][td] ][ mark[tp][d] ] += g[i];//这里确实有点问题
        }
        savevar[ mark[p][td] ] = tmp;
    }
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            flagflag = 0;
            int y,p,d;
            cin>>n>>m>>y>>p>>d;
            memset(savevar,0,sizeof(savevar));//真是神奇的错误啊
            for(int i=1;i<=m;i++)
            {
                int tmp;
                scanf("%d",&tmp);
                tg[i] = tmp;
                g[i] = (double)tmp/100;
            }
            if(y==p)
            {
                printf("0.00
    ");
                continue;
            }
            memset(mark,-1,sizeof(mark));
    //        if(d==-1)
    //        {
    //            if(p==0) d = 0;
    //            else d = 1;
    //        }
            if(p==0) d=0;
            else if(p==n-1) d=1;
            id = 0;
            memset(a,0,sizeof(a));
            dfs(p,d,y);
    //        if(flagflag == 0)
    //        {
    //            printf("Impossible !
    ");
    //            continue;
    //        }
            for(int i=0;i<id;i++)//有id个等式
            {
                a[i][id] = -savevar[i];
            }
            equ = var = id;
    //        for(i=0;i<equ;i++)
    //            for(j=0;j<var+1;j++){
    //                scanf("%lf",&a[i][j]);
    //            }
            //Debug();
            //cout<<endl;
            int free_num=Guass();
    //        co++;
    //        printf("Case #%d:",co);
    //        if(free_num==0)
    //        {
    //            printf("%.2lf",(iabs(x[0])<EPS?EPS:x[0]));
    //            for(int i=1;i<var;i++) printf(" %.2lf",(iabs(x[i])<EPS?EPS:x[i]));
    //            cout<<endl;
    //        }else cout<<"Can't solve it."<<endl;
            //无求无穷多解的情况
        }
        return 0;
    }
    
    /*
     100
     4 2 0 1 0
     0 100
     4 10 0 1 0
     10 10 5 5 0 20 20 20 2 8
     10 5 5 0 -1
     10 20 30 20 20
     10 100 5 9 -1
     1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
     10 4 1 2 0
     0 20 0 80
     100 4 1 2 0
     0 20 0 80
     100 100 5 9 0
     1 1 1 1 1 1 1 1 1 1 0 1 1 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
     100 4 1 2 0
     0 20 1 79
     */
    

      

  • 相关阅读:
    [转]android刷新后R.java不见了
    adb常用指令
    [转]Intent跳转到系统应用中的拨号界面、联系人界面、短信界面及其他
    effective c/C++
    七种布局显示方式效果及实现
    修改Tabhost样式和字体大小的方法
    [转]android中SoundRecorder
    java中的IO整理
    在xp下面下载Android源代码
    linux网络 (二):无线网络操作
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/5754902.html
Copyright © 2011-2022 走看看