1. 程式人生 > 其它 >【題解】【P4042 [AHOI2014/JSOI2014]騎士遊戲】

【題解】【P4042 [AHOI2014/JSOI2014]騎士遊戲】

【P4042 [AHOI2014/JSOI2014]騎士遊戲】

最短路好題。
如果考慮dp的話,設\(f_i\)表示第i個怪物被消滅的最小代價,那麼顯然有\(f_i=min(k_i,s_i+\sum\limits_{j=1}^{r_i}f_{vj})\)
但是題目中,怪物會形成一個環,具有後效性。
這裡有兩種方法:

  1. 藉助spfa思想,既然不知道從哪開始轉移,那就全部進隊,全都轉移,不斷進行鬆弛,直到佇列為空。但是這裡有一點需要注意,傳統的spfa進行更新時,都是一對多的更新,但這個題目中的更新屬於多對一的更新。因此佇列中不再維護“可能更新其他點的點”,而是維護“可能被其他點更新的點”。
  2. 藉助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;
}