【题解】P7831 [CCO 2021] Travelling Merchant
一:【题意】
二:【解法】
拓扑删点,删掉的点 \(ans=-1\)
剩下的点一定有解
\(dp_u=min(max(r_i,dp_v-p_i))\)
但是给定的是一张有向图,存在环,如何在环上 \(dp\) 呢
我们注意到转移方程中的 \(max(r_i,dp_v-p_i)\) ,如果 \(r_i>=dp_v-p_i\) 则取值为 \(r_i\) 为一个定值
所以我们先找出最大的 \(r\) ,更新入点,删边
当一个点 \(x\) 出度为 \(0\) ,那么决策完毕,就可以用 \(x\) 更新其他点了
如果图上又全是环,重新找最大的 \(r\) ,然后更新,对于这个我们可以提前对边排序
三:【代码】
#include<bits/stdc++.h>
#define Pair pair<int,int>
#define v first
#define id second
#define inf 2e9
using namespace std;
const int N=2e5+10;
struct node{
int v,r,p,id;
};
vector<node> mp[N];
struct Edge{
int u,v,r,p,id;
bool operator<(Edge b){
return r>b.r;
}
}edg[N];
int ind[N];
int dp[N];
int vis[N];
int main(){
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++) dp[i]=inf;
for(int i=1;i<=m;i++){
int u,v,r,p;cin>>u>>v>>r>>p;
edg[i]={u,v,r,p,i};
mp[v].push_back({u,r,p,i});
ind[u]++;
}
sort(edg+1,edg+1+m);
queue<int> q;
for(int i=1;i<=n;i++){
if(!ind[i]) q.push(i);
}
for(int i=1;i<=m;i++){
while(q.size()){
int u=q.front();q.pop();
for(auto e:mp[u]){
int v=e.v,r=e.r,p=e.p,id=e.id;
if(vis[id]) continue;
vis[id]=1;
if(dp[u]!=inf) dp[v]=min(dp[v],max(r,dp[u]-p));
ind[v]--;
if(ind[v]==0) q.push(v);
}
}
if(!vis[edg[i].id]){
vis[edg[i].id]=1;
int u=edg[i].u,r=edg[i].r;
dp[u]=min(dp[u],r);
ind[u]--;
if(ind[u]==0) q.push(u);
}
}
for(int i=1;i<=n;i++){
if(dp[i]==inf) cout<<-1<<" ";
else cout<<dp[i]<<" ";
}
return 0;
}

浙公网安备 33010602011771号