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);
    }
}
posted @ 2024-09-10 22:02  liyixin  阅读(4)  评论(0编辑  收藏  举报