2018 NOIP 全套资料下载-提取码:072k
【问题描述】
银河大盗驾驶着“太空飞船”在银河系的各星球之间逃窜,宇宙警察们追捕行动开始了。作为计算机专家,需要为警察局计算某时刻银河大盗在各星球出现的概率。
银河系有n个星球,用1~n的整数为每个星球标号,星球之间的交通工具是“太空飞船”。任何两个星球之间都可以由太空船直达,从星球i到星球j直达需要消耗的能量为tij(加仑),当然从j到i也需要消耗这么多能量。银河大盗总是选择最节约能量的路径从一个星球逃窜到另一个星球。具体来说,若 t 时刻盗匪在星球 i ,则在 t+1 时刻,他逃到星球 j 的概率:P=(dist(i,j))/(sum(i)),其中,dist(i,j)表示星球i到星球j的最小能量;sum(i)=∑_(k=1)^n▒dist(i,k) 。
现在,给定0 时刻盗匪在每个星球出现的概率。请求T时刻盗匪出现在每个星球的概率。
【输入格式】
从文件robbers.in中读入数据。
输入的第1行两个整数 n 和 T,他们的意义如题目描述。第2行 n 个实数,表示 0 时刻盗匪在个星球出现的概率(保证概率加起来为 1),第i个实数表示在第i个星球出现的概率。接下来 n 行每行 n 个整数,第 i 行第 j 个数表示星球 i 到星球 j 需要消耗的能量。 保证第 i 行第 i 个数为 0 且第 i 行第 j 个数等于第 j 行第 i 个数(即给出的矩阵是关于副对角线对称的)。
【输出格式】
输出到文件robbers.out中。
输出共 n 行,第 i 行表示 T 时盗匪出现在星球 i 的概率,保留六位小数。
【输入样例】
3 2
0 1 0
0 1 4
1 0 2
4 2 0
【输出样例】
0.400000
0.350000
0.250000
【数据规模与约定】
对于 50% 的数据,T<=20。
对于 100% 的数据,n<=200,T<=109。保证对于每个星球dist 的和值在 int 范围。
————————————————————————————————————————————————————
好好解题:
50分直接dp模拟,100分用矩阵快速幂优化。只要会打快速幂就没什么问题(表示看出来了是矩阵快速幂但是之前没有写过就现场打了一次打对了,滑稽)。
注意几个问题:矩阵定义在结构体里面会使用栈空间,所以务必记得扩栈还有写成全局变量。于是快速幂千万不要打递归写法嗯。
哲学思想:
化学告诉我们万物都趋向于稳定的状态
所以
在无限久远的未来
强盗在每个星球的概率会趋近于一个定值
所以说
不会快速幂的小伙伴
在T大于2000的时候直接改成2000来递推就可以过啦!!!!!!厉害吧?!?!(当然不是所有题目都有效的,只是这个在时间可以承受的范围之内就可以在精度要求范围之内不发生变化了,不过有些题目的正解还真的是这个)
好好解题:
#include
#include
#include
#include
#include
#include
#include
#include
#include
int N,T;
int dist[maxn][maxn],sum[maxn],cnt;
double f[maxn],p[maxn][maxn];
struct matrix{
int x,y;
double A[maxn][maxn];
matrix(){
x=y=0;
memset(A,0,sizeof(A));
}
friend matrix operator * (matrix a,matrix b)
{
matrix c;
c.x=a.x,c.y=b.y;
for(int i=1;i<=c.x;i++)
for(int j=1;j<=c.y;j++)
for(int k=1;k<=a.y;k++)
c.A[i][j]+=a.A[i][k]*b.A[k][j];
return c;
}
}ans,pp,re,tmp;
void data_in()
{
scanf("%d%d",&N,&T);
for(int i=1;i<=N;i++)
scanf("%lf",&f[i]);
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
scanf("%d",&dist[i][j]);
}
void ready()
{
for(int k=1;k<=N;k++)
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
sum[i]+=dist[i][j];
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
p[i][j]=1.0dist[i][j]/sum[i];
}
void work()
{
if(T!=0)
{
pp.x=pp.y=N;
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
pp.A[i][j]=p[j][i];
tmp=re=pp;
for(int j=1;(1<<j)<=T;j++)
{
if((1<<j)&T) re=retmp;
tmp=tmptmp;
}
ans.x=N,ans.y=1;
for(int i=1;i<=N;i++)
ans.A[i][1]=f[i];
ans=reans;
for(int i=1;i<=N;i++)
printf("%.6lf\n",ans.A[i][1]);
}
else
{
for(int i=1;i<=N;i++)
printf("%.6lf\n",f[i]);
}
}
int main()
{
freopen(“robbers.in”,“r”,stdin);
freopen(“robbers.out”,“w”,stdout);
data_in();
ready();
work();
return 0;
}
原文:https://blog.csdn.net/qq_39439314/article/details/78165634