1. 程式人生 > >NOIP-模擬試題之--銀河大盜

NOIP-模擬試題之--銀河大盜

2018 NOIP 全套資料下載

【問題描述】
銀河大盜駕駛著“太空飛船”在銀河系的各星球之間逃竄,宇宙警察們追捕行動開始了。作為計算機專家,需要為警察局計算某時刻銀河大盜在各星球出現的概率。
銀河系有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
#include
#include
using namespace std;
const int maxn=205;

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=re
tmp;
tmp=tmptmp;
}
ans.x=N,ans.y=1;
for(int i=1;i<=N;i++)
ans.A[i][1]=f[i];
ans=re
ans;
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