用高斯消元法(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 }
原文地址:https://www.cnblogs.com/ka200812/p/2630184.html