【P4042 [AHOI2014/JSOI2014]骑士游戏】
最短路好题。
如果考虑dp的话,设\(f_i\)表示第i个怪物被消灭的最小代价,那么显然有\(f_i=min(k_i,s_i+\sum\limits_{j=1}^{r_i}f_{vj})\)
但是题目中,怪物会形成一个环,具有后效性。
这里有两种方法:
- 借助spfa思想,既然不知道从哪开始转移,那就全部进队,全都转移,不断进行松弛,直到队列为空。但是这里有一点需要注意,传统的spfa进行更新时,都是一对多的更新,但这个题目中的更新属于多对一的更新。因此队列中不再维护“可能更新其他点的点”,而是维护“可能被其他点更新的点”。
- 借助dij的思想,\(f_i\)能从第二个式子转移的必要条件是任意\(f_{vj},有f_{vj}<f_i\),于是我们可以对dp值建一个堆,每次取最小值去更新其他点,如果被更新的dp值已经更新完了,将其加入堆内;如果其需要更新的dp值已经被弹出,那么显然有那个dp值小于当前dp值所以更新无用
Dij
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define rep( i, s, t ) for( register int i = s; i <= t; ++ i )
#define re register
#define int long long
int read() {
char cc = getchar(); int cn = 0, flus = 1;
while(cc < '0' || cc > '9') { if( cc == '-' ) flus = -flus; cc = getchar(); }
while(cc >= '0' && cc <= '9') cn = cn * 10 + cc - '0', cc = getchar();
return cn * flus;
}
const int N = 2e5 + 5 ;
const int M = 1e6 + 5 ;
int n, s[N], K[N], dp[N], vis[N], ans[N], R[N] ;
vector<int> mp[N] ;
struct node {
int id, w ;
bool operator < ( const node& x ) const {
return w > x.w ;
}
};
priority_queue<node> q ;
signed main()
{
n = read() ; int x, siz ;
rep( i, 1, n ) {
s[i] = read(), K[i] = read(), R[i] = read() ;
rep( j, 1, R[i] ) x = read(), mp[x].push_back(i) ;
q.push((node){ i, K[i] }), dp[i] = s[i] ;
}
while( !q.empty() ) {
int u = q.top().id, w = q.top().w ; q.pop() ;
if( vis[u] ) continue ;
vis[u] = 1, ans[u] = w, siz = mp[u].size() - 1 ;
rep( i, 0, siz ) {
int v = mp[u][i] ;
if( vis[v] || dp[v] > K[v] ) continue ;
R[v] --, dp[v] += w ;
if( R[v] == 0 ) q.push((node){ v, dp[v] }) ;
}
}
printf("%lld\n", ans[1] ) ;
return 0;
}
Spfa
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
register int x=0,w=1;
register char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-'){ch=getchar();w=-1;}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar(); }
return x*w;
}
const int N=2e5+100;
int n,d[N],s[N];
vector<int>son[N],fa[N];
int vis[N];
void spfa()
{
queue<int>q;
memset(vis,1,sizeof vis);
for(int i=1;i<=n;++i) q.push(i);
while(q.size())
{
int x=q.front();q.pop();
vis[x]=0;
int w=s[x];
for(int i=0;i<son[x].size();++i){
w+=d[son[x][i]];
}
if(w<d[x]){
d[x]=w;
for(int i=0;i<fa[x].size();++i){
int y=fa[x][i];
if(vis[y]==0) {
vis[y]=1;
q.push(y);
}
}
}
}
}
void add(int x,int y)
{
son[x].push_back(y);
fa[y].push_back(x);
}
signed main()
{
n=read();
for(int i=1;i<=n;++i)
{
s[i]=read();
d[i]=read();
int x=read(),y;
while(x--){
y=read();
add(i,y);
}
}
spfa();
cout<<d[1];
return 0;
}