题意:
你需要从 1 1 1走到 n n n,初始速度是 t t t,某些地方有自行车,每个位置自行车有 p i p_i pi的概率是坏掉的,如果自行车没坏可以骑上自行车,速度是 r r r,可以一直骑着到终点。
1 ≤ t ≤ r ≤ 1 e 4 , 1 ≤ n , m ≤ 1 e 5 , 0 ≤ k ≤ 18 , 1 ≤ a i ≤ n , 0 ≤ p i ≤ 100 1\le t\le r\le 1e4,1\le n,m\le 1e5,0\le k\le 18,1\le a_i\le n,0\le p_i\le 100 1≤t≤r≤1e4,1≤n,m≤1e5,0≤k≤18,1≤ai≤n,0≤pi≤100
思路:
注意到
k
k
k很小,可以选择状压一下到哪些有自行车的位置,设
f
[
s
t
a
t
e
]
[
j
]
f[state][j]
f[state][j]表示当前选择的自行车位置集合为
s
t
a
t
e
state
state,最后一次停在
j
j
j的时候,到终点的期望,显然我们需要倒着推,转移方程:
f
[
s
t
a
t
e
]
[
i
]
=
m
i
n
(
f
[
s
t
a
t
e
]
[
i
]
,
(
f
[
s
t
a
t
e
∣
(
1
<
<
j
)
]
[
j
]
+
d
i
s
[
i
]
[
a
[
j
]
]
/
t
)
∗
p
[
i
]
+
d
i
s
[
i
]
[
n
]
∗
(
1
−
p
[
i
]
)
/
r
)
f[state][i]=min(f[state][i],(f[state|(1<<j)][j]+dis[i][a[j]]/t)*p[i]+dis[i][n]*(1-p[i])/r)
f[state][i]=min(f[state][i],(f[state∣(1<<j)][j]+dis[i][a[j]]/t)∗p[i]+dis[i][n]∗(1−p[i])/r)
让后选择记忆化或者循环都可以,这个题由于有边界问题,显然选 d f s dfs dfs更好写。
记忆化:
#include<bits/stdc++.h>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define pb push_back
using namespace std;
const int N=100010,INF=0x3f3f3f3f,mod=1e9+7;
typedef long long LL;
typedef pair<int,int> PII;
int t,r;
int n,m,k;
vector<PII>v[N];
int dis[21][N];
int a[N],p[N];
bool st[N];
void dijkstra(int s) {
priority_queue<PII,vector<PII>,greater<PII>>q;
memset(st,0,sizeof(st));
memset(dis[s],0x3f,sizeof(dis[s]));
dis[s][a[s]]=0;
q.push({0,a[s]});
while(q.size()) {
auto u=q.top(); q.pop();
int id=u.Y;
if(st[id]) continue;
st[id]=1;
for(auto x:v[id]) {
if(dis[s][x.X]>dis[s][id]+x.Y) {
dis[s][x.X]=dis[s][id]+x.Y;
q.push({dis[s][x.X],x.X});
}
}
}
}
double f[1<<20][20],P[1010];
LL d[1<<20][20];
double dfs(int state,int pos) {
if(f[state][pos]!=-1) return f[state][pos];
double tmp=P[pos]*dis[pos][n]/t+(1-P[pos])*dis[pos][n]/r;
for(int i=0;i<k;i++) {
if(i==pos) continue;
if(state&(1<<i)) continue;
tmp=min(tmp,P[pos]*(dfs(state|(1<<i),i)+1.0*dis[pos][a[i]]/t)+(1-P[pos])*dis[pos][n]/r);
}
return f[state][pos]=tmp;
}
void solve() {
scanf("%d%d%d%d",&t,&r,&n,&m);
while(m--) {
int a,b,c; scanf("%d%d%d",&a,&b,&c);
v[a].pb({b,c});
v[b].pb({a,c});
}
scanf("%d",&k); a[k]=1; p[k]=100;
for(int i=0;i<k;i++) scanf("%d%d",&a[i],&p[i]);
for(int i=0;i<=k;i++) dijkstra(i);
if(dis[k][n]==INF) {
puts("-1");
return;
}
for(int i=0;i<=k;i++) P[i]=1.0*p[i]/100;
for(int i=0;i<1<<20;i++) for(int j=0;j<20;j++) f[i][j]=-1;
printf("%.8f\n",dfs(0,k));
}
int main() {
int _=1;
while(_--) {
solve();
}
}
循环二进制
#include<bits/stdc++.h>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define pb push_back
using namespace std;
const int N=100010,INF=0x3f3f3f3f,mod=1e9+7;
typedef long long LL;
typedef pair<int,int> PII;
int t,r;
int n,m,k;
vector<PII>v[N];
int dis[21][N];
int a[N],p[N];
bool st[N];
void dijkstra(int s) {
priority_queue<PII,vector<PII>,greater<PII>>q;
memset(st,0,sizeof(st));
memset(dis[s],0x3f,sizeof(dis[s]));
dis[s][a[s]]=0;
q.push({0,a[s]});
while(q.size()) {
auto u=q.top(); q.pop();
int id=u.Y;
if(st[id]) continue;
st[id]=1;
for(auto x:v[id]) {
if(dis[s][x.X]>dis[s][id]+x.Y) {
dis[s][x.X]=dis[s][id]+x.Y;
q.push({dis[s][x.X],x.X});
}
}
}
}
double f[1<<20][20],P[1010];
void solve() {
scanf("%d%d%d%d",&t,&r,&n,&m);
while(m--) {
int a,b,c; scanf("%d%d%d",&a,&b,&c);
v[a].pb({b,c});
v[b].pb({a,c});
}
scanf("%d",&k); a[k]=1; p[k]=100;
for(int i=0;i<k;i++) scanf("%d%d",&a[i],&p[i]);
for(int i=0;i<=k;i++) dijkstra(i);
if(dis[k][n]==INF) {
puts("-1");
return;
}
for(int i=0;i<=k;i++) P[i]=1.0*p[i]/100;
for(int i=0;i<1<<20;i++) for(int j=0;j<20;j++) f[i][j]=1e18;
for(int i=(1<<k)-1;i>=1;i--) {
for(int x=0;x<k;x++) {//当前走到的点
if(i&(1<<x)) {
f[i][x]=(1-P[x])*dis[x][n]/r+P[x]*dis[x][n]/t;
for(int y=0;y<k;y++) {//下一个要到的点
if(x==y) continue;
if((i&1<<y)) continue;
f[i][x]=min(f[i][x],(1-P[x])*dis[x][n]/r+P[x]*(1.0*dis[x][a[y]]/t+f[i|(1<<y)][y]));
}
}
}
}
double ans=1.0*dis[k][n]/t;
for(int y=0;y<k;y++) {
int x=1<<y,i=0;
ans=min(ans,1.0*dis[k][a[y]]/t+f[i|(1<<y)][y]);
}
printf("%.8f\n",ans);
}
int main() {
int _=1;
while(_--) {
solve();
}
}