HDU--4418(概率DP,高斯消元)
2015-04-16 12:21:13
思路:这道题琢磨了很久....
题意比较晦涩:给一个0~N-1的数列,有一个起点,有初始方向,在数列里面走,如果碰到边界就换方向。再给出每次走 i (i<=M) 步的概率,问走到终点的期望步数。
先是自己YY了一个拆点的方法,乱搞了一天... 过了样例但是跑不过一些特殊数据... wa 弃疗
看了别人的博客...
核心点:
(1)将N个点扩张成:2×(N-1)个点,N =2*(N-1)
如:01234 -> 01234321,这样以来只用往右走:
此时“右走”在4的左边(01234)代表右走,在4的右边(4321)代表左走,所以根据方向确定起点后就不用再管方向,一律右走。
所以如果起始方向为左,则 X = (N - X) % N
(2)首先要从起点 / (终点)跑一遍 bfs 来判断某些点是否能从起点到达 / (能否到达终点)。注意起点只有一个,而终点有两个!
(3)剩下的就是经典的带环概率DP问题了,用高斯消元求解
Ei = E(i+1)*P1 + E(i+2)*P2 + E(i+3)*P3 + ... + E(i+M)*PM + 1
-> -Ei + E(i+1)*P1 + E(i+2)*P2 + E(i+3)*P3 + ... + E(i+M)*PM = -1
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 const int MAXN = 210; 25 const double eps = 1e-8; 26 27 int T; 28 int N,M,Y,X,D; 29 double P[MAXN]; 30 double g[MAXN][MAXN]; 31 bool can[MAXN]; 32 33 void Gauss(){ 34 int i,col; 35 for(i = 0,col = 0; col < N; ++i,++col){ 36 int r = i; 37 for(int j = i + 1; j < N; ++j) 38 if(fabs(g[j][col]) > fabs(g[r][col])) r = j; 39 if(r != i) for(int j = col; j <= N; ++j) swap(g[r][j],g[i][j]); 40 if(fabs(g[i][col]) < eps){ 41 --i; 42 continue; 43 } 44 for(int j = N; j >= col; --j) g[i][j] /= g[i][col]; 45 for(int k = 0; k < N; ++k) if(k != i){ 46 for(int j = N; j >= col; --j) 47 g[k][j] -= g[k][col] * g[i][j]; 48 } 49 } 50 } 51 52 void Debug(){ 53 for(int i = 0; i < N; ++i){ 54 for(int j = 0; j <= N; ++j) printf("%.2f ",g[i][j]); 55 puts(""); 56 } 57 } 58 59 void Bfs(){ 60 queue<int> Q; 61 while(!Q.empty()) Q.pop(); 62 MEM(can,false); 63 can[Y] = can[(N - Y) % N] = true; 64 Q.push(Y); 65 Q.push((N - Y) % N); 66 while(!Q.empty()){ 67 int cur = Q.front(); Q.pop(); 68 FOR(j,1,M){ 69 int nxt = (cur - j + N) % N; 70 if(P[j] >= eps && !can[nxt]){ 71 can[nxt] = true; 72 Q.push(nxt); 73 } 74 } 75 } 76 } 77 78 int main(){ 79 scanf("%d",&T); 80 while(T--){ 81 MEM(g,0); 82 scanf("%d%d%d%d%d",&N,&M,&Y,&X,&D); 83 FOR(i,1,M) scanf("%lf",&P[i]),P[i] /= 100.0; 84 if(X == Y){ 85 printf("0.00\n"); 86 continue; 87 } 88 N = (N - 1) * 2; 89 if(D > 0) X = (N - X) % N; 90 Bfs(); 91 if(!can[X]){ 92 printf("Impossible !\n"); 93 continue; 94 } 95 REP(i,N){ 96 if(i == Y || i == (N - Y) % N){ 97 g[i][i] = 1; 98 g[i][N] = 0; 99 continue; 100 } 101 g[i][i] = -1; 102 FOR(j,1,M){ 103 int nxt = (i + j) % N; 104 if(!can[nxt]) continue; 105 g[i][nxt] += P[j]; 106 g[i][N] -= j * P[j]; 107 } 108 } 109 //Debug(); 110 Gauss(); 111 for(int i = 0; i < N; ++i) if(fabs(g[i][X]-1) < eps){ 112 printf("%.2f\n",g[i][N]); 113 break; 114 } 115 } 116 return 0; 117 }
... YY后的尸体,勿念 TAT
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 const int MAXN = 210; 25 const double eps = 1e-8; 26 27 int T; 28 int N,M,Y,X,D,NN; 29 double P[MAXN]; 30 double g[MAXN * 2][MAXN * 2]; 31 bool can[MAXN * 2]; 32 33 bool Gauss(){ 34 int i,col; 35 for(i = 0,col = 0; col < NN; ++i,++col){ 36 int r = i; 37 for(int j = i + 1; j < NN; ++j) 38 if(fabs(g[j][col]) > fabs(g[r][col])) r = j; 39 if(r != i) for(int j = col; j <= NN; ++j) swap(g[r][j],g[i][j]); 40 if(fabs(g[i][col]) < eps){ 41 --i; 42 continue; 43 } 44 for(int j = NN; j >= col; --j) g[i][j] /= g[i][col]; 45 for(int k = 0; k < NN; ++k) if(k != i){ 46 for(int j = NN; j >= col; --j) 47 g[k][j] -= g[k][col] * g[i][j]; 48 } 49 } 50 for(; i < NN; ++i) if(!(fabs(g[i][NN]) < eps)) return false; 51 return true; 52 } 53 54 void Debug(){ 55 for(int i = 0; i < NN; ++i){ 56 for(int j = 0; j <= NN; ++j) printf("%.2f ",g[i][j]); 57 puts(""); 58 } 59 } 60 61 void Bfs(){ 62 queue<int> Q; 63 while(!Q.empty()) Q.pop(); 64 MEM(can,false); 65 can[Y << 1] = can[Y << 1|1] = true; 66 Q.push(Y << 1); 67 Q.push(Y << 1|1); 68 while(!Q.empty()){ 69 int cur = Q.front(); Q.pop(); 70 int cur_pos = cur / 2; 71 FOR(j,1,M){ 72 int tj = j % (2 * N); 73 int pos; 74 int f = cur & 1; 75 if((!f && cur_pos == N - 1) || (f && cur_pos == 0)) f ^= 1; 76 if(!f){ 77 pos = cur_pos + tj; 78 if(pos >= N) pos = 2*N - pos - 2,f ^= 1; 79 if(pos < 0) pos = -pos,f ^= 1; 80 if(pos >= N) pos = 2*N - pos - 2,f ^= 1; 81 if(pos < 0) pos = -pos,f ^= 1; 82 } 83 else{ 84 pos = cur_pos - tj; 85 if(pos < 0) pos = -pos,f ^= 1; 86 if(pos >= N) pos = 2*N - pos - 2,f ^= 1; 87 if(pos < 0) pos = -pos,f ^= 1; 88 if(pos >= N) pos = 2*N - pos - 2,f ^= 1; 89 } 90 pos = pos << 1|f; 91 if(!can[pos]){ 92 can[pos] = true; 93 Q.push(pos); 94 } 95 } 96 } 97 } 98 99 int main(){ 100 scanf("%d",&T); 101 while(T--){ 102 MEM(g,0); 103 scanf("%d%d%d%d%d",&N,&M,&Y,&X,&D); 104 NN = N << 1; 105 FOR(i,1,M) scanf("%lf",&P[i]),P[i] /= 100.0; 106 if(X == Y){ 107 printf("0.00\n"); 108 continue; 109 } 110 Bfs(); 111 if(can[X << 1|D] == false){ 112 printf("Impossible !\n"); 113 continue; 114 } 115 //for(int i = 0; i < NN; ++i) 116 // printf("can[%d] : %d\n",i,can[i]); 117 REP(i,N){ 118 if(i == Y){ 119 g[i << 1][i << 1] = 1; 120 g[i << 1][NN] = 0; 121 g[i << 1|1][i << 1|1] = 1; 122 g[i << 1|1][NN] = 0; 123 continue; 124 } 125 g[i << 1][i << 1] = -1; 126 g[i << 1|1][i << 1|1] = -1; 127 FOR(j,1,M){ //走j步 128 int tj = j % (2 * N); 129 int pos,f = 0; 130 //向右走到i 131 pos = i + tj; 132 if(pos >= N) pos = 2*N - pos - 2,f ^= 1; //next position 133 if(pos < 0) pos = -pos,f ^= 1; 134 if(pos >= N) pos = 2*N - pos - 2,f ^= 1; //next position 135 if(pos < 0) pos = -pos,f ^= 1; 136 137 //printf("i : %d , pos : %d\n",i,pos); 138 //if(pos == 0 && f == 1) pos = pos << 1; 139 //else if(pos == N - 1 && f == 0) pos = pos << 1|1; 140 //else 141 pos = pos << 1|f; 142 if(can[pos]){ 143 g[i << 1][pos] += P[j]; 144 g[i << 1][NN] -= j * P[j]; 145 } 146 //向左走到i 147 f = 1; 148 pos = i - tj; 149 if(pos < 0) pos = -pos,f ^= 1; //next position 150 if(pos >= N) pos = 2*N - pos - 2,f ^= 1; 151 if(pos < 0) pos = -pos,f ^= 1; //next position 152 if(pos >= N) pos = 2*N - pos - 2,f ^= 1; 153 154 //printf("i : %d , pos : %d\n",i,pos); 155 //if(pos == 0 && f == 1) pos = pos << 1; 156 //else if(pos == N - 1 && f == 0) pos = pos << 1|1; 157 //else 158 pos = pos << 1|f; 159 if(can[pos]){ 160 g[i << 1|1][pos] += P[j]; 161 g[i << 1|1][NN] -= j * P[j]; 162 } 163 } 164 } 165 //Debug(); 166 if(Gauss()){ 167 for(int i = 0; i < NN; ++i) if(fabs(g[i][X << 1|D]-1) < eps){ 168 //printf("row : %d\n",i); 169 printf("%.2f\n",g[i][NN]); 170 break; 171 } 172 } 173 else printf("Impossible !\n"); 174 } 175 return 0; 176 }