A. 24ab-day1 好吃
A. 24ab-day1 好吃
给你一个有向图,每个点有权值 \(x,y\)。一个人从任意一个点 \(u\) 出发,每次可以走到他能走到的任意一个点 \(v\),若 \(v\) 也可以到达 \(u\),要付出 \(x_v\) 的代价,否则付出 \(y_v\) 的代价。
发现如果 \(u,v\) 在一个强连通分量里,就会花费 \(x_v\) 的代价。而且强连通分量里的点是可以两两互达的。因此考虑 tarjan 缩点,对于每一个强连通分量,求出这个强连通分量里选 \(j\) 个点的最小花费。只有第一个点会花费代价 \(y\),其他都是 \(x\),因此我们枚举 \(y\),然后对 \(x\) 排序,贪心选小的即可,这里的时间复杂度是 \(O(n^2\log n)\) 的。
缩点后的图是一个 DAG。这个可以按拓扑序 DP。设 \(dp_{i,j}\) 表示到第 \(i\) 个点一共选了 \(j\) 个餐厅的最小代价。转移枚举前面与它相连的点,还要枚举第 \(i\) 个点选几个餐厅,时间是 \(O(n^4)\) 的。考虑优化。枚举状态一定是有必要的,枚举我的决策也应该很有必要,可以去掉枚举前面的决策点。用数组 \(g\) 存选 \(x\) 个点,前面的点最优的决策,这个一次是 \(O(n^2)\) 的,一共 \(n\) 个点,处理 \(n\) 次,这样 DP 的时间就是 \(O(n^3)\) 了。
Code
#include<bits/stdc++.h>
// #define LOCAL
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
using namespace std;
typedef long long ll;
const int N=505,M=N*N,inf=1e9;
int n;
struct node{
int x,y,scc;
}a[N];
int u,v;
struct edge{
int to,ne;
}e[M],g[M];
int head[N],cnt;
void adde(int u,int v){
e[++cnt]={v,head[u]};
head[u]=cnt;
}
int x,y,f;
int headg[N],cntg;
void addg(int u,int v){
g[++cntg]={v,headg[u]};
headg[u]=cntg;
}
int dfn[N],low[N];
int sum,num;
int st[N],top;
map<pair<int,int>,bool> mp;
int du[N];
vector<int> vec[N];
void findscc(int u){
dfn[u]=low[u]=++num;
st[++top]=u;
for(int i=head[u];i;i=e[i].ne){
int v=e[i].to;
if(!dfn[v]){
findscc(v);
low[u]=min(low[u],low[v]);
}else if(!a[v].scc){
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u]){
a[u].scc=++sum;
vec[sum].push_back(u);
for(int i=head[u];i;i=e[i].ne){
int v=e[i].to;
int us=a[u].scc,vs=a[v].scc;
if(us==vs||vs==0||mp[{us,vs}]) continue;
mp[{us,vs}]=1;
addg(us,vs);
du[vs]++;
}
while(st[top]!=u){
a[st[top]].scc=sum;
vec[sum].push_back(st[top]);
for(int i=head[st[top]];i;i=e[i].ne){
int v=e[i].to;
int us=sum,vs=a[v].scc;
if(us==vs||vs==0||mp[{us,vs}]) continue;
mp[{us,vs}]=1;
addg(us,vs);
du[vs]++;
}
top--;
}
top--;
}
}
int af[N][N];
bool cmp(int n,int m){
return a[n].x<a[m].x;
}
int b[N];
void findsort(){
memset(af,0x3f,sizeof(af));
rep(i,1,sum){
sort(vec[i].begin(),vec[i].end(),cmp);
int siz=vec[i].size();
rep(j,0,siz-1){
int u=vec[i][j];
b[j]=a[u].x+(j==0?0:b[j-1]);
}
af[i][0]=0;
rep(j,0,siz-1){
rep(k,0,siz-1){
int u=vec[i][k];
int s=a[u].y;
s+=(j==0?0:(k<=j-1?b[j]-a[u].x:b[j-1]));
af[i][j+1]=min(af[i][j+1],s);
}
}
}
}
int dp[N][N];
int dpx[N][N];
int tp[N];
vector<int> fr[N];
void DP(){
queue<int> que;
rep(i,1,sum){
if(du[i]==0) que.push(i);
}
while(!que.empty()){
int u=que.front();
tp[++tp[0]]=u;
que.pop();
for(int i=headg[u];i;i=g[i].ne){
int v=g[i].to;
fr[v].push_back(u);
du[v]--;
if(du[v]==0) que.push(v);
}
}
memset(dp,0x3f,sizeof(dp));
memset(dpx,0x3f,sizeof(dpx));
rep(i,1,sum){
int u=tp[i];
rep(j,0,n) dp[u][j]=af[u][j];
for(int v:fr[u]){
rep(j,0,n){
dpx[u][j]=min(dpx[u][j],dp[v][j]);;
}
}
rep(j,1,n){
int siz=vec[u].size();
rep(k,0,min(siz,j)){
dp[u][j]=min(dp[u][j],af[u][k]+dpx[u][j-k]);
}
}
}
}
int main(){
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("my.out","w",stdout);
#endif
sf("%d",&n);
rep(i,1,n){
sf("%d%d%d",&x,&y,&f);
a[i]={x,y};
rep(j,1,f){
sf("%d",&v);
adde(i,v);
}
}
rep(i,1,n) if(!a[i].scc)findscc(i);
findsort();
DP();
int ans;
rep(i,1,n){
ans=dp[1][i];
rep(j,2,sum){
ans=min(ans,dp[j][i]);
}
if(ans>inf) break;
pf("%d\n",ans);
}
}
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18407311