[hdu4418]Time travel

Time travel

题解

无论如何,这题面是真的难理解

如果我们用f_{i}来表示从点i走到点y的期望步数的话,我们很容易得到一个方程f_{i}=\sum_{j=1}^{m}p_{j}(f_{i+j}+j)

由于这种逆推式不能转化为状态转移方程式来dp求解,我们只能用高斯消元来对其进行求解。

于是,可以得到方程式f_{i}+\sum_{j=1}^{m}-p_{j}f_{i+j}=\sum_{j=1}^{m}p_{j}j。再用高斯消元进行求解。

可是,它可以向两个方向走,我们就把原来的数列再往后翻折一半,将(0,1,2,3,4,...,n-1)变成(0,1,...,n-1,,n-2...,2,1)

之后再通过bfs求出可达的点,如果终点不可达就直接输出,否则,再此基础上建出期望方程,解出来输出f_{x}的值即可。

注意需特判起点与终点是否不同,否则会因n=1的情况RE。

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
typedef long long LL;
const double INF=1e9;
const double eps=1e-9;
int n,m,N,M,X,Y,D,tot;
double arr[305][305],ans[305],p[305];
bool frecnt[305];
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
void swap1(int x,int y,int len){for(int i=0;i<=len;i++)swap(arr[x][i],arr[y][i]);}
bool Zero(double x){return Fabs(x)>eps;}
int gauss(){
	int t=0,p=0;
	/*for(int i=0;i<m;i++){
		for(int j=0;j<=n;j++)
			printf("%lf ",arr[i][j]);
		puts("");		
	}*/
	for(;p<m&&t<m;p++,t++){
		int maxx=p;
		for(int j=p+1;j<m;j++)
			if(Fabs(arr[j][t])>Fabs(arr[maxx][t]))
				maxx=j;
		if(p!=maxx)swap1(p,maxx,n);
		if(Fabs(arr[p][t])<eps){p--;continue;}
		for(int j=p+1;j<m;j++){
			if(Fabs(arr[j][t])<eps)continue;
			double tmp=arr[j][t]/arr[p][t];
			for(int k=t;k<=n;k++)
				arr[j][k]-=arr[p][k]*tmp;
		}
	}
	for(int i=p;i<m;i++)if(Fabs(arr[i][t])>eps)return -1;
	if(p<m){
		int num=0,freidx;
		for(int i=p-1;i>=0;i--){
			num=0;double tmp=arr[i][n];
			for(int j=0;j<n;j++)
				if(Fabs(arr[i][j])>eps&&frecnt[j])
					num++,freidx=j;
			if(num>1)continue;tmp=arr[i][n];
			for(int j=0;j<n;j++)
				if(Fabs(arr[i][j])>eps&&j!=freidx)
					tmp-=arr[i][j]*ans[j];
			ans[freidx]=tmp/arr[i][freidx];frecnt[freidx]=0;
		}
		return m-p;
	}
	for(int i=m-1;i>=0;i--){
		double tmp=arr[i][n];
		for(int j=i+1;j<n;j++)
			tmp-=arr[i][j]*ans[j];
		ans[i]=tmp/arr[i][i];
	}
	return 0;
}
bool vis[305];
queue<int> q;
void bfs(int s){
	while(!q.empty())q.pop();
	q.push(s);vis[s]=1;
	while(!q.empty()){
		int t=q.front();q.pop();
		for(int i=1;i<=M;i++){
			int v=(t+i)%N;
			if(Zero(p[i])&&!vis[v])
				q.push(v),vis[v]=1;
		}
	}
}
signed main(){
	int t;scanf("%d",&t);
	while(t--){
		memset(arr,0,sizeof(arr));
		memset(ans,0,sizeof(ans));
		memset(vis,0,sizeof(vis));
		memset(frecnt,1,sizeof(frecnt));double sum=0;
		scanf("%d %d %d %d %d",&N,&M,&Y,&X,&D);
		for(int i=1;i<=M;i++)scanf("%lf",&p[i]),p[i]/=100.0,sum+=1.0*i*p[i];
		if(X==Y){puts("0.00");continue;}
		N=2*(N-1);n=m=N;if(D>0)X=(N-X)%N;bfs(X);
		if(!vis[Y]&&!vis[(N-Y)%N]){puts("Impossible !");continue;}
		for(int i=0;i<N;i++){
			arr[i][i]=1;
			if(!vis[i]){arr[i][N]=INF;continue;}
			if(i==Y||i==(N-Y)%N){arr[i][N]=0;continue;}
			arr[i][N]=sum;int now=i;
			for(int j=1;j<=M;j++){
				now++;if(now==N)now=0;
				arr[i][now]-=p[j];
			}
		}
		int fc=gauss();
		if(fc<0)puts("Impossible !");
		else printf("%.2lf\n",ans[X]);
	}
	return 0;
}

谢谢!!!

posted @ 2020-09-09 09:55  StaroForgin  阅读(18)  评论(0)    收藏  举报  来源