E - Ingredients 拓扑排序+01背包

让人想犯罪 __ 提交于 2019-12-06 05:37:00

题源:https://codeforces.com/gym/101635/attachments

题意: n行,每行给定字符串s1,s2,s3代表一些菜谱名。s2和s3是煮成是的必要条件,然后给出c和v,分别代表s1的消耗和收获;

   (注意:这个消耗并不可能是s1的真正消耗和收获,s1的最后消耗和收获是得加上s2和s3的)

   然后问在不用超过C消耗的情况下最大收获是多少?

分析:这里我们可以想象到,一道有条件的菜要做成是要若干个“前提”菜做成的,这个过程就是拓扑排序!我们对于每个s1,s2,s3编号后就是拓扑排序了,s2,s3,就是相当于给予s1一个入度;

   所有每次拓扑我们就枚举已经做成的s2和s3给最优的c和v给s1,然后最后对所有的菜进行01背包找出答案

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int inf=0x3f3f3f3f;
const ll INF=1e18;
const int N=1e6+6;
const int M=1e5+5;
struct node{
    int u,id;
};
vector<node>g[N];
ll dp[M],cc[M],vv[M],ind[M],book[N];
ll c[N],v[N];
int ID,cnt;
char s1[50],s2[50],s3[50];
map<int,int>mp;
map<string ,int>sign;
queue<int>que;
int getid(string x){
    if(sign[x]==0){
        sign[x]=++ID;
    }
    return sign[x];
}
int main(){
    int C,n;
    scanf("%d%d",&C,&n);
    for(int i=1;i<=n;i++){
        scanf("%s%s%s%lld%lld",s1,s2,s3,&c[i],&v[i]);
        int z=getid(s1);
        int x=getid(s2);
        int y=getid(s3);
        ind[z]++;
        cc[z]=inf;
        mp[i]=z;
        g[x].pb({y,i});
        g[y].pb({x,i});
    }
    for(int i=1;i<=ID;i++){
        if(ind[i]==0)
            que.push(i);
    }
    while(!que.empty()){
        int x=que.front();
        que.pop();
        for(int i=0;i<g[x].size();i++){
            node nowv=g[x][i];
            int y=nowv.u,id=nowv.id,z=mp[id];
            if(!book[id]&&ind[y]==0){
                book[id]=1;
                ll cost=cc[x]+cc[y]+c[id];
                ll val=vv[x]+vv[y]+v[id];
                if(cc[z]>cost||(cc[z]==cost&&vv[z]<val)){
                    cc[z]=cost;
                    vv[z]=val;
                }
                if(--ind[z]==0)
                    que.push(z);
            }
            
        }
    }

    dp[0]=0;
    for(int i=1;i<=ID;i++){
        for(int j=C;j>=0;j--)
            if(j-cc[i]>=0)
                dp[j]=max(dp[j],dp[j-cc[i]]+vv[i]);
    }
    ll maxx=0;
    ll lasc=0;
    for(int i=1;i<=C;i++){
        if(dp[i]>maxx){
            maxx=dp[i];
            lasc=i;
        }
    }
    printf("%lld\n%lld\n",maxx,lasc);
    return 0;
    
}
View Code

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!