码迷,mamicode.com
首页 > 其他好文 > 详细

hdu6007 spfa+完全背包

时间:2017-10-15 22:37:13      阅读:233      评论:0      收藏:0      [点我收藏+]

标签:clu   bre   name   题解   数组下标   开头   下标   scanf   多少   

题意:给你M,N,K,代表你有M点法力值,N个物品,K个制造方式

接下来N行,如果以1开头则代表既能卖又能合成,0代表只能卖。

然后K行,每行第一个数是要合成的东西,第二个数代表有几对,每对第一个数是那种物品,第二个是需要几个。

 

注意不能直接合成的可以通过制造方式来合成。然后问你花费完所有的法力制造的东西,能获得最大的金钱是多少

 

题解:首先处理出来对于所有物品所需要消耗的最小法力值,然后就是做一下完全背包就可以了。

消耗最小法力值可以通过spfa获得,一个技巧就是对于同属一个目标产物的原材料,可以用一个fa[]数组来指向目标产物的vector的数组下标.目标产物有两个vector,其中一个代表了是哪几种原材料,然后另一个对应的是这几种原材料的个数。

然后再利用head[]数组,得知一个目标产物的原材料的边的编号tot一定是连续的,那么就把这连续一段的边的编号指为当前目标产物的两个vector的数组下标就可以了。

具体详见代码。---强迫症是从0开始计的,所以说建边的时候要减一

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
int dp[10086],sell[208],pct[208],head[208];
bool vis[208];
int M,N,K,op,n,T,tas=1,tot;
struct node
{
    int v,next;
} e[100861];
void add(int u,int v)
{
    e[tot].v=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
vector<int>U[208];
vector<int>num[208];
int fa[100861];
void spfa()
{
    queue<int>Q;
    for(int i=0; i<N; ++i) if(pct[i]!=INF)
        {
            Q.push(i),vis[i]=1;
        }
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        vis[u]=0;
        for(int i=head[u]; ~i; i=e[i].next)
        {
            bool ok=1;
            int ans=0;
            for(int j=0; j<(int)U[fa[i]].size(); ++j)
            {
                if(pct[U[fa[i]][j]]==INF)
                {
                    ok=0;
                    break;
                }
                ans+=pct[U[fa[i]][j]]*num[fa[i]][j];
            }
            if(!ok) continue;
            if(ans<pct[e[i].v])
            {
                pct[e[i].v]=ans;
                if(!vis[e[i].v]) Q.push(e[i].v),vis[e[i].v]=1;
            }
        }
    }
}
int main()
{
    for(scanf("%d",&T); T--;)
    {
        memset(head,-1,sizeof(head));
        memset(pct,INF,sizeof(pct));
        tot=0;
        scanf("%d%d%d",&M,&N,&K);
        for(int i=0; i<N; ++i)
        {
            scanf("%d",&op);
            if(op==0) scanf("%d",&sell[i]);
            else scanf("%d%d",&pct[i],&sell[i]);
        }
        int now=0;
        for(int i=0; i<K; ++i)
        {
            int tar,par,ne,nn;
            scanf("%d%d",&tar,&par);
            if(!par) continue;
            U[now].clear();
            num[now].clear();
            int last=tot;
            --tar;
            for(int j=0; j<par; ++j)
            {
                scanf("%d%d",&ne,&nn);
                --ne;
                add(ne,tar);
                U[now].push_back(ne);
                num[now].push_back(nn);
            }
            for(int j=last; j<tot; ++j) fa[j]=now;
            ++now;
        }
        spfa();
        memset(dp,0,sizeof(dp));
        for(int i=0; i<N; ++i) for(int j=pct[i]; j<=M; ++j) dp[j]=max(dp[j],dp[j-pct[i]]+sell[i]);
        printf("Case #%d: %d\n",tas++,dp[M]);
    }
}

 

hdu6007 spfa+完全背包

标签:clu   bre   name   题解   数组下标   开头   下标   scanf   多少   

原文地址:http://www.cnblogs.com/mfys/p/7674352.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!