ZOJ3524Crazy Shopping(完全背包+拓扑排序)经典

H - Crazy Shopping
Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu

Description

Because of the 90th anniversary of the Coherent & Cute Patchouli (C.C.P), Kawashiro Nitori decides to buy a lot of rare things to celebrate.

TH_CuteNitori.jpg

Kawashiro Nitori is a very shy kappa (a type of water sprite that live in rivers) and she lives on Youkai MountainYoukai Mountain is a dangerous place full of Youkai, so normally humans are unable to be close to the mountain. But because of the financial crisis, something have changed. For example, Youkai Mountain becomes available for tourists.

On the mountain there are N tourist attractions, and there is a shop in each tourist attraction. To make the tourists feel more challenging (for example, to collect all kinds of souvenirs), each shop sells only one specific kind of souvenir that can not buy in any other shops. Meanwhile, the number of the souvenirs which sells in each shop is infinite. Nitori also knows that each kind of souvenir has a weight TWi(in kilogram) and a value TVi.

Now Nitori is ready to buy souvenirs. For convenience, Nitori numbered the tourist attraction from 1 to N. At the beginning Nitori is located at the tourist attraction X and there are M roads connect some pairs of tourist attractions, and each road has a length L. However, because Youkai Mountain is very steep, all roads are uni-directional. By the way, for same strange reason, the roads ensure that when someone left one tourist attraction, he can not arrive at the same tourist attraction again if he goes along the road.

Nitori has one bag and the maximal load is W kilogram. When there are K kilogram things in Nitori's bag, she needs to cost K units energy for walking one unit length road. Of course she doesn't want to waste too much energy, so please calculate the minimal cost of energy ofNitori when the value is maximal.

Notice: Nitori can buy souvenir at tourist attraction X, and she can stop at any tourist attraction. Also, there are no two different roads between the same two tourist attractions. Moreover, though the shop sells different souvenirs, it is still possible for two different kinds of souvenir have the same weight or value.

Input

There are multiple test cases. For each test case:

The first line contains four numbers N (1 <= N <= 600) - the number of tourist attractions, M (1 <= M <= 60000) - the number of roads,W (1 <= W <= 2000) - the load of the bag and X (1 <= X <= N) - the starting point of Nitori.

Then followed by N lines, each line contains two integers which means the shop on tourist attraction i sells the TWi and TVi things (1 <=TWi <= W, 1 <= TVi <= 10000).

Next, there are M lines, each line contains three numbers, XiYi and Li, which means there is a one-way road from tourist attraction Xi toYi, and the length is Li (1 <= Xi,Yi <= N, 1 <= Li <= 10000).

Output

For each test case, output the answer as the description required.

Sample Input

4 4 10 1
1 1
2 3
3 4
4 5
1 2 5
1 3 4
2 4 4
3 4 5

Sample Output

0
Hint

It's no hard to know that Nitori can buy all things at tourist attraction 2, so she cost 0 unit energy

题意:在多个有向子图中,给一个起点,这个人背着一个容量为W大的包装物品,从一点走到另一个点,而且花费体力为:包里的物品重量*两点间的距离,每一个点有无数的同种商品,每种商品都有重量和价值,问在得到最大价值的同时最少花费多少。


一开始我用了深搜+完全背包TLE,后来看了网上的全都用了拓扑排序+完全背包,下面分析一下用拓扑排序的好处:

因为该图是一个有向无环图,那么一有顶点入度为0,而入度为0的点一定不能更新,所以我们只要把与之相连的点更新了,就可以不必再用该点,而正是如此,就可以一层层的消去点,须起的每一条路都只用了一次。如果是用深搜,一条路可能不只走一次,这就须花很多时间,这就是超时的原因。

#include<stdio.h>
#include<vector>
#include<string.h>
#include<iostream>
using namespace std;

#define ll int
const int INF=999999999;

struct node
{
    ll cost,value;
};
struct sss
{
    int u,s;
};
node dp[602][2002];
vector<sss>map[605];
ll oder[605],top,in[605],N,M,W,X;
node Node[605],ans;
ll S[602][602];

void init()
{
     for(ll i=1;i<=N;i++)
        {
            for(ll j=0;j<=W;j++)
                dp[i][j].value = 0;
            dp[i][0].cost=0;
            map[i].clear();
            in[i] = 0;
        }
}
void tope_oder()
{
    top=0;
    for(int i=1;i<=N;i++)
        if(!in[i])
            oder[++top]=i;
    int k=1,v,u;
    while(k<=top)
    {
        v=oder[k++];
        for(int i=0;i<map[v].size(); i++)
        {
            u=map[v][i].u;
            in[u]--;
            if(!in[u])
                oder[++top]=u;
        }
    }
}
void solve()
{
    int vist[605]={0};

    vist[X]=1;
    for(int j=Node[X].cost; j<=W; j++)
    if(dp[X][j-Node[X].cost].value!=-1)
    {
        dp[X][j].value=dp[X][j-Node[X].cost].value+Node[X].value;
        dp[X][j].cost=0;
    }

    for(int t=1;t<=top;t++)
    {
        int x=oder[t];
        if(vist[x]==0)
            continue;

        int len=map[x].size(),u,s;
        for(int k=0;k<len; k++)
        {
            u = map[x][k].u;
            s = map[x][k].s;
            vist[u]=1;

            for(ll w=0; w<=W; w++)
            if(dp[x][w].value!=-1)
            {
                if(dp[u][w].value<dp[x][w].value)
                {
                    dp[u][w].value=dp[x][w].value;
                    dp[u][w].cost=dp[x][w].cost+w*s;
                }
                else if(dp[u][w].value==dp[x][w].value)
                    if(dp[u][w].cost>dp[x][w].cost+w*s)
                    dp[u][w].cost=dp[x][w].cost+w*s;
            }

            for(ll w=Node[u].cost; w<=W;w++)
            if(dp[u][w-Node[u].cost].value!=-1)
            {
                if(dp[u][w].value<dp[u][w-Node[u].cost].value+Node[u].value)
                {
                    dp[u][w].value=dp[u][w-Node[u].cost].value+Node[u].value;
                    dp[u][w].cost=dp[u][w-Node[u].cost].cost;
                }
                else if(dp[u][w].value==dp[u][w-Node[u].cost].value+Node[u].value)
                       if(dp[u][w].cost>dp[u][w-Node[u].cost].cost )
                          dp[u][w].cost=dp[u][w-Node[u].cost].cost ;
            }
        }
    }
    ans.value=0;
    ans.cost=0;
    for(ll i=1;i<=N ; i++)
        if(vist[i])
        for(ll v=1;v<=W;v++)
            if(dp[i][v].value>=ans.value)
            {
                if(ans.value<dp[i][v].value)
                    ans.cost=dp[i][v].cost;
                else if(dp[i][v].cost<ans.cost)
                    ans.cost=dp[i][v].cost;
                ans.value=dp[i][v].value;
            }
}

int main()
{
    sss p;
    while(scanf("%d%d%d%d",&N,&M,&W,&X)>0)
    {
        for(ll i=1;i<=N;i++)
            scanf("%d%d",&Node[i].cost,&Node[i].value);

        init();
        ll v,u,s;
        while(M--)
        {
            scanf("%d%d%d",&v,&p.u,&p.s);
            map[v].push_back(p),in[p.u]++;
        }

        tope_oder();
        solve();

        printf("%d\n",ans.cost);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值