# Optimizing DP with Dij's idea

## 1, Content

If the state transition equation of \ (DP \) is \ (f[i]=min\{f[i],\sum f[j]+k \} \)

Then we can consider optimizing it with the idea of \ (Dij \)

Because if the \ (f \) value of a point is the smallest, no other point can affect it

Therefore, every time we take the smallest point from the heap and update other points

## 2, Examples

### 1. Luogu P4745 [CERC2017]Gambling Guide

Portal

#### analysis

According to the general practice of expectation questions, we set \ (f[u] \) as the expected cost from \ (U \) to the end \ (n \)

Set \ (du[u] \) as the outgoing degree of node \ (U \)

Then \ (f [u] = \ frac {\ sum {U - > V} min (f [u], f [v])} {Du [u]} + 1 \)

We will find that this formula contains both \ (f[u] \) itself and the point \ (f[v] \) adjacent to \ (f[u] \)

But we can be sure that if \ (f[v] < f[u] \), then \ (f[v] \) will certainly contribute to \ (f[u] \)

Therefore, we can use the idea of \ (Dij \) to open a small root heap and take out the smallest one each time to update others

Because the current value is the smallest, there must be no other point that can affect it

We set \ (u \) to be updated \ (cnt \) times by the \ (f \) value of the point adjacent to it, and the sum of these values is \ (sum \)

Then \ (f[u]=\frac{sum+(du[u]-cnt[u]) \times f[u]}{du[u]}+1 \)

Available \ (f[u]=\frac{sum+du[u]}{cnt} \)

#### code

#include<cstdio>
#include<cstring>
#include<queue>
const int maxn=6e5+5;
int x=0,fh=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
struct asd{
int to,next;
}b[maxn];
b[tot].to=bb;
}
struct jie{
int num;
double jl;
jie(){}
jie(int aa,double bb){
num=aa,jl=bb;
}
bool operator < (const jie &A) const{
return jl>A.jl;
}
};
int n,m,du[maxn],cnt[maxn];
double sum[maxn],f[maxn];
bool vis[maxn];
std::priority_queue<jie> q;
void dij(){
q.push(jie(n,0));
while(!q.empty()){
int now=q.top().num;
q.pop();
if(vis[now]) continue;
vis[now]=1;
int u=b[i].to;
if(vis[u]) continue;
cnt[u]++;
sum[u]+=f[now];
f[u]=(du[u]+sum[u])/cnt[u];
q.push(jie(u,f[u]));
}
}
}
int main(){
for(int i=1;i<=m;i++){
int aa,bb;
du[aa]++,du[bb]++;
}
dij();
printf("%.10f\n",f[1]);
return 0;
}



### 2. Li Qing (internal question)

Portal

#### analysis

We set the cost of eliminating the head of (I) as \ (f[i] \)

Then \ (f [i] = min (f [i], a [i] + \ sum, f [J], B [i]) \)

Similarly, we throw all the \ (f \) values into the small root heap at the beginning

Update the first value of other elements every time

#### code

#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<iostream>
#include<cstdlib>
const int maxn=6e5+5;
typedef long long ll;
struct asd{
int to,next;
}b[maxn];
int n;
b[tot].to=bb;
}
struct jie{
int num;
ll jl;
jie(){}
jie(int aa,ll bb){
num=aa,jl=bb;
}
bool operator < (const jie &A) const{
return jl>A.jl;
}
};
ll a[maxn],f[maxn];
int k[maxn];
bool vis[maxn];
std::priority_queue<jie> q;
void dij(){
while(!q.empty()){
int now=q.top().num;
q.pop();
if(vis[now]) continue;
vis[now]=1;
if(k[now]==0) f[now]=std::min(f[now],a[now]);
int u=b[i].to;
if(!vis[u]){
a[u]+=f[now];
k[u]--;
if(k[u]==0) q.push(jie(u,a[u]));
}
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld%d",&a[i],&f[i],&k[i]);
q.push(jie(i,f[i]));
for(int j=1;j<=k[i];j++){
int aa;
scanf("%d",&aa);