【題解】【P4042 [AHOI2014/JSOI2014]騎士遊戲】
阿新 • • 發佈:2021-10-25
【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\)
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; }