• 用高斯消元法(gauss)求解一类期望问题


    http://acm.zjut.edu.cn/ShowProblem.aspx?ShowID=1423

    Description:

    由于山体滑坡,DK被困在了地下蜘蛛王国迷宫。为了抢在DH之前来到TFT,DK必须尽快走出此迷宫。此迷宫仅有一个出口,而由于大BOSS的力量减弱影响到了DK,使DK的记忆力严重下降,他甚至无法记得他上一步做了什么。所以他只能每次等概率随机的选取一个方向走。当然他不会选取周围有障碍的地方走。如DK周围只有两处空地,则每个都有1/2的概率。现在要求他平均要走多少步可以走出此迷宫。

    Input:

    先是一行两个整数N, M(1<=N, M<=10)表示迷宫为N*M大小,然后是N行,每行M个字符,'.'表示是空地,'E’表示出口,'D’表示DK,'X’表示障碍。      

    Output:

    如果DK无法走出或要超过1000000步才能走出,输出tragedy!,否则输出一个实数表示平均情况下DK要走几步可以走出迷宫,四舍五入到小数点后两位。

    Sample Input:

    1 2
    ED
    3 3
    D.X
    .X.
    X.E
    

    Sample Output:

    1.00
    tragedy!
    
    首先对地图节点重新标号。
    假设E[i]表示DK从i点开始走出迷宫的期望值。那么E[i]=(E[a1]+E[a2]+E[a3]+...+E[an])/n+1,其中a1...an是i的相邻节点。
    那么对于每一个DK可达的节点来说,都可以为它建立这样的一个方程。
    现在假设DK可达的点有N个,那么我们最终将会得到N元一次方程组。最后利用高斯消元解出E[No[S]]。其中S是DK的起点,No[S]是重标号后的起点
    这里要重点注意的是,我们联立方程的时候,一定要注意DK可达这个条件,不然就会导致无解的情况。
    View Code
      1 #include<iostream>
      2 #include<string>
      3 #include<cmath>
      4 #include<algorithm>
      5 using namespace std;
      6 #define MAXN 800
      7 
      8 double mat[MAXN][MAXN];
      9 char map[40][40];
     10 int num[40][40];
     11 
     12 struct node
     13 {
     14     int x;
     15     int y;
     16 };
     17 node Star,end;
     18 int n,m,len;
     19 int di[4][2]={1,0,0,1,-1,0,0,-1};
     20 int cut;
     21 
     22 int isok(int x,int y)
     23 {
     24     return x >= 0 && x < n && y >= 0 && y < m && map[x][y]!='X';
     25 }
     26 
     27 node queue[2*MAXN];
     28 int head,tail;
     29 
     30 void fillnum(int x,int y) //对地图进行重新标号,标号从0开始
     31 {
     32     num[x][y]=++cut;
     33     tail=head=0;
     34     node e,q;
     35     e.x=x;e.y=y;
     36     queue[tail++]=e;
     37     while(head<tail)
     38     {
     39         e=queue[head++];
     40         for(int i=0;i<4;i++)
     41         {
     42             q.x=e.x+di[i][0];
     43             q.y=e.y+di[i][1];
     44             if(isok(q.x,q.y) && num[q.x][q.y]==-1)
     45             {
     46                 num[q.x][q.y]=++cut;
     47                 queue[tail++]=q;
     48             }
     49         }
     50     }
     51 }
     52 
     53 bool gauss(int n) 
     54 { 
     55     int i, j, row, idx; 
     56     double buf, maxx; 
     57     for(row = 0; row < n; row ++) 
     58     { 
     59         for(maxx = 0, i = row; i < n; i ++)
     60         { 
     61             if(maxx < fabs(mat[i][row])) 
     62             { 
     63                 maxx = fabs(mat[i][row]); 
     64                 idx = i; 
     65             } 
     66         } 
     67         if(maxx == 0)
     68             continue;
     69         if(idx != row) 
     70         { 
     71             for(i = row; i <= n; i ++) 
     72                 swap(mat[row][i], mat[idx][i]); 
     73         } 
     74         for(i = row + 1; i < n; i ++)
     75         { 
     76             if(fabs(mat[i][row])<1e-8)
     77                 continue;
     78             buf = mat[i][row] / mat[row][row]; 
     79             for(j = row; j <= n; j ++) 
     80                 mat[i][j] -= buf * mat[row][j]; 
     81         } 
     82     } 
     83     for(i = n - 1; i >= 0; i --) 
     84     { 
     85         for(j = i + 1; j < n; j ++) 
     86             mat[i][n] -= mat[i][j] * mat[j][j]; 
     87         mat[i][i] = mat[i][n] / mat[i][i]; 
     88     } 
     89     return true; 
     90 } 
     91 
     92 int main()
     93 {
     94     int i,j,k,x,y;
     95     freopen("D:\\in.txt","r",stdin);
     96     while(scanf("%d%d",&n,&m)!=EOF)
     97     {
     98         len=0;
     99         for(i=0;i<n;i++)
    100         {
    101             scanf("%s",map[i]);
    102             for(j=0;j<m;j++)
    103             {
    104                 if(map[i][j]=='D')
    105                 {
    106                     Star.x=i;
    107                     Star.y=j;
    108                 }
    109                 else if(map[i][j]=='E')
    110                 {
    111                     end.x=i;
    112                     end.y=j;
    113                 }
    114             }
    115         }
    116         memset(num,255,sizeof(num));
    117         cut=-1;
    118         fillnum(Star.x,Star.y);
    119         if(num[end.x][end.y]==-1)
    120         {
    121             printf("tragedy!\n");
    122             continue;
    123         }
    124         memset(mat,0,sizeof(mat));
    125         for(i=0;i<n;i++)  //建立N元一次方程组
    126         {
    127             for(j=0;j<m;j++)
    128             {
    129                 if(num[i][j]!=-1)
    130                 {
    131                     int now=num[i][j];
    132                     int count=0;
    133                     for(k=0;k<4;k++)
    134                     {
    135                         x=i+di[k][0];y=j+di[k][1];
    136                         if(isok(x,y))
    137                         {
    138                             mat[now][num[x][y]]=-1;
    139                             count++;
    140                         }
    141                         mat[now][now]=count;
    142                         mat[now][cut+1]=count;
    143                     }
    144                 }
    145             }
    146         }
    147         x=num[end.x][end.y];
    148         memset(mat[x],0,sizeof(mat[x]));
    149         mat[x][x]=1;
    150         if(gauss(cut+1))
    151         {
    152             if(mat[num[Star.x][Star.y]][num[Star.x][Star.y]]<=1000000)
    153                 printf("%0.2lf\n",mat[num[Star.x][Star.y]][num[Star.x][Star.y]]);
    154             else
    155                 printf("tragedy!\n");
    156         }
    157         else
    158         {
    159             printf("tragedy!\n");
    160         }
    161     }
    162     return 0;
    163 }

    http://acm.zjut.edu.cn/ShowProblem.aspx?ShowID=1317

    Description:

    m个人位于正m边形的顶点上,彼此抛掷飞盘。他们共有两个飞盘,且开始时这两个飞盘位于相距为n的两个人的手中(相邻两个人相距为1,依此类推)。在每次抛掷时两个飞盘被同时抛出,飞盘都以1/2的概率被抛到掷飞盘的人左边相邻的人,1/2的概率被抛到右边相邻的人。此过程一直进行,直到两个飞盘被掷到同一个人手中,求此抛掷飞盘的游戏平均情况下(期望)会在抛掷几次后结束。

    Input:

    每行有两个整数m (2<m<=100),n (0 < n < m)。

    这题我们以两个飞盘的距离为状态进行转移。

    那么E[n]=E[n+2]/4+E[n-2]/4+E[n]/2+1,化简成:2E[n]-E[n+2]-E[n-2]=4。

    首先对于两个飞盘给定的起始距离n,我们可以先搜索一下可否到达状态0,如果不行,则直接输出INF。在搜索的过程中,顺便把重新标号也进行了。为什么这题也要重新标号呢?

    因为该题中,假设m是偶数,那么对于任意的n,n+1和n-1都是不可达的状态。请一定记得,如果方程组中有不可达的点的话,就会导致无解的情况!

    接下来对每一个可达的状态建立一个如上的方程,最后用高斯消元法解除E[No[n]]即可!

    View Code
      1 #include<iostream>
      2 #include<string>
      3 #include<cmath>
      4 #include<stdio.h>
      5 #include<memory.h>
      6 #include<algorithm>
      7 using namespace std;
      8 #define maxn 200
      9 
     10 double mat[maxn][maxn];
     11 int num[maxn];
     12 int n,m;
     13 int cut;
     14 
     15 int getnum(int x) //获取x的状态,对于一个环来说,x和m-x是一样的,我们取小的
     16 {
     17     if(x<0)
     18         x=-x;
     19     if(x>n/2)
     20         x=n-x;
     21     return x;
     22 }
     23 
     24 void dfs(int x) //重标号
     25 {
     26     num[x]=cut++;
     27     int y=getnum(x+2);
     28     if(num[y]==-1)
     29         dfs(y);
     30     y=getnum(x-2);
     31     if(num[y]==-1)
     32         dfs(y);
     33 }
     34 
     35 bool gauss(int n) 
     36 { 
     37     int i, j, row, idx; 
     38     double buf, maxx; 
     39     for(row = 0; row < n; row ++) 
     40     { 
     41         for(maxx = 0, i = row; i < n; i ++)
     42         { 
     43             if(maxx < fabs(mat[i][row])) 
     44             { 
     45                 maxx = fabs(mat[i][row]); 
     46                 idx = i; 
     47             } 
     48         } 
     49         if(maxx == 0) return false; 
     50         if(idx != row) 
     51         { 
     52             for(i = row; i <= n; i ++) 
     53                 swap(mat[row][i], mat[idx][i]); 
     54         } 
     55         for(i = row + 1; i < n; i ++)
     56         { 
     57             buf = mat[i][row] / mat[row][row]; 
     58             for(j = row; j <= n; j ++) 
     59                 mat[i][j] -= buf * mat[row][j]; 
     60         } 
     61     } 
     62     for(i = n - 1; i >= 0; i --) 
     63     { 
     64         for(j = i + 1; j < n; j ++) 
     65             mat[i][n] -= mat[i][j] * mat[j][j]; 
     66         mat[i][i] = mat[i][n] / mat[i][i]; 
     67     } 
     68     return true; 
     69 } 
     70 
     71 int main()
     72 {
     73     int i,len;
     74     freopen("D:\\in.txt","r",stdin);
     75     while(scanf("%d%d",&n,&m)==2)
     76     {
     77         memset(num,255,sizeof(num));
     78         if(m>n/2)
     79             m=n-m;
     80         cut=0;
     81         dfs(m);
     82 //         for(i=0;i<=n/2;i++)
     83 //             cout<<num[i]<<" ";
     84 //         cout<<endl;
     85         if(num[0]==-1)
     86         {
     87             printf("INF\n");
     88             continue;
     89         }
     90         memset(mat,0,sizeof(mat));
     91         len=n/2;
     92         int now,j;
     93         for(i=0;i<=len;i++)
     94         {
     95             if(num[i]!=-1)
     96             {
     97                 now=num[i];
     98                 mat[now][now]=2;
     99                 mat[now][cut]=4;
    100                 j=getnum(i-2);
    101                 mat[now][num[j]]-=1;
    102                 j=getnum(i+2);
    103                 mat[now][num[j]]-=1;
    104             }
    105         }
    106         j=num[0];
    107         memset(mat[j],0,sizeof(mat[j]));
    108         mat[j][j]=1;
    109 //         for(i=0;i<cut;i++)
    110 //         {
    111 //             for(j=0;j<=cut;j++)
    112 //                 cout<<mat[i][j]<<" ";
    113 //             cout<<endl;
    114 //         }
    115         if(gauss(cut))
    116         {
    117             printf("%0.2lf\n",mat[num[m]][num[m]]);
    118         }
    119         else
    120         {
    121             printf("INF\n");
    122         }
    123     }
    124     return 0;
    125 }
  • 相关阅读:
    继承
    类和对象
    Scanner类
    面向对象思想
    final关键字
    The difference between text mode and binary mode with file streams
    Linux下常见权限操作相关命令
    Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext
    手动运行jar包,指定配置文件
    jdk 1.8.0_131 Class JavaLaunchHelper is implemented
  • 原文地址:https://www.cnblogs.com/ka200812/p/2630184.html
Copyright © 2020-2023  润新知