zoj 3524 Crazy Shopping 拓扑排序+完全背包 ★★★☆

Crazy Shopping

Time Limit: 3 Seconds       Memory Limit: 65536 KB

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 ofYoukai, so normally humans are unable to be close to the mountain. But because of the financial crisis, something have changed. For example, Youkai Mountainbecomes 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 Xand 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 of Nitori 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 to Yi, 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.



Author: DAI, Longa


必须先说坑点,也不算是吧。

就是该图不一定是个连通图,就是说有些点从起点出发是不可能到达的。

我就在这个地方使劲的wa,最后终于发现这个问题了。


背包这是肯定的,然而先要进行拓扑排序

因为动态规划是讲究顺序性的,DAG上的动态规划。

先拓扑排序,之后把顺序记录下来,按着这个顺序访问,

首先可以把起点vis[]=1,遍历排好序的元素时,如果vis[]=0,则跳出。

访问某个结点时,把它能到达的结点vis[]都赋值为1。

这样可以满足顺序性,即当前进行dp的某点进行了对过去和现在的一个完美总结。

然后后面的点才好方便调用它的结论。


dp[x][v]:表示在点x,容量为v的背包装载的最大价值。

从a点到b点旅行。要将dp[a][v]全部考虑到dp[b][v]中。

开一个数组dpc[x][v]:表示在点x,装载容量为v的背包,所需消耗的体力最小值。


这里有很重要的分析:

就是说对于某个点,用同样的容量,他能继承到达它之前经历的点能达到的最大价值。

同时用这么多容量花费的体力要>=之前点同容量所需消耗的体力


因为题目要求创造最大价值,所以dp里存的必须是某体积下的最大价值。不用担心会有其它问题。


到达每一点,先继承进行状态转移(这个步骤也可以在之前访问该点的前驱点时,对该点状态转移,而且这样最好

然后再考虑该地点的物品加入背包。


以下代码中的方法,比我题解所说要麻烦,不仅存储了更多的边,而且多用了一次dfs。


简化的方法我题解已经说了。








#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<cctype>
#include<utility>
#pragma comment(linker, "/STACK:102400000,102400000")
#define PI (4.0*atan(1.0))
#define eps 1e-10
#define sqr(x) ((x)*(x))
#define FOR0(i,n)  for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n)  for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n)  for(int i=(n) ;i>=0 ;i--)
#define  lson   ind<<1,le,mid
#define rson    ind<<1|1,mid+1,ri
#define MID   int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)
#define mk    make_pair
#define _f     first
#define _s     second
using namespace std;
//const int INF=    ;
typedef long long ll;
//const ll inf =1000000000000000;//1e15;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
const int INF =0x3f3f3f3f;
const int maxn= 600+20   ;
const int maxV=2000+20    ;

int n,m,V,st;
int cost[maxn],val[maxn];
int deg[maxn];
vector<int >from[maxn];
vector<int >G[maxn];

vector<int > indexx;
int maxi;ll ans;

int dp[maxn][maxV];
ll dpc[maxn][maxV];
bool vis[maxn];

struct Edge
{
    int s,t,w;
    Edge(){}
    Edge(int s,int t,int w):s(s),t(t),w(w){}

};
vector<Edge >edges;
void init()
{
    edges.clear();
    indexx.clear();

    FOR1(i,n)
    {
        deg[i]=0;
        G[i].clear();
        from[i].clear();
    }
}

inline void add_edge(int s,int t,int w)
{
     edges.push_back(Edge(s,t,w));
     int m=edges.size()-1;
     G[s].push_back(m);
     from[t].push_back(m);
     deg[t]++;
}


void topsort()
{
    queue<int >q;
    FOR1(i,n)
    {
        if(!deg[i])   q.push(i);
    }
    while(!q.empty())
    {
        int x=q.front();q.pop();
        indexx.push_back(x);
        for(int i=0;i<G[x].size();i++)
        {
            Edge &e=edges[G[x][i]] ;
            int y=e.t;
            if(--deg[y]==0)  q.push(y);
        }

    }
}

void DP()
{
    maxi=0,ans=0;
    memset(dp,0,sizeof dp);
    memset(dpc,0,sizeof dpc);
    for(int i=0;i<indexx.size();i++)
    {
        int x=indexx[i];

        if(!vis[x])  continue;
      //  cout<<x<<endl;
      //  cout<<"edge"<<endl;
       for(int j=0;j<from[x].size();j++)
       {


           int s=edges[ from[x][j]].s;
           int w=edges[ from[x][j]].w;
     //      cout<<s<<endl;
          for(int v=0;v<=V;v++)
          {
              if(dp[x][v]>dp[s][v])  continue;

              if(dp[x][v]==dp[s][v])
              dpc[x][v]=min(  dpc[s][v]+ v*w  , dpc[x][v]     );

              else dpc[x][v]=dpc[s][v]+ v*w;

              dp[x][v]=dp[s][v];
          }

       }
   //    cout<<"!!!"<<endl;
           for(int v=cost[x];v<=V;v++)
           {

             if(dp[x][v]>dp[x][v-cost[x]]+val[x])  continue;
             if(dp[x][v]==dp[x][v-cost[x]]+val[x])
             {
                 dpc[x][v]=min( dpc[x][v],dpc[x][v-cost[x] ]     );
             }
             else
             {
                 dp[x][v]=dp[x][v-cost[x]]+val[x];
                 dpc[x][v]=dpc[x][v-cost[x] ];
             }
                 if(maxi<dp[x][v])    maxi= dp[x][v],ans=dpc[x][v];
              else if(maxi==dp[x][v])  ans=min(ans,dpc[x][v]);


           }

           /*
           for(int v=cost[x];v<=V;v++)
           {
                if(maxi<dp[x][v])    maxi= dp[x][v],ans=dpc[x][v];
              else if(maxi==dp[x][v])  ans=min(ans,dpc[x][v]);
           }*/



      //  cout<<"maxi "<<maxi<<endl;
      //  cout<<"ans "<<ans<<endl;

    }


}

void work()
{
    maxi=0,ans=0;
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])  continue;
        for(int v=0;v<=V;v++)
        {
            if(dp[i][v]>maxi)
            {
                maxi=dp[i][v];
                ans=dpc[i][v];
            }
            else if(dp[i][v]==maxi)
            {
                ans=min(ans,dpc[i][v]);
            }
        }
    }
}

void dfs(int x)
{
    for(int i=0;i<G[x].size();i++)
    {
        Edge e=edges[G[x][i]];
        int y=e.t;
        if(vis[y])  continue;
        vis[y]=1;
        dfs(y);
    }
}
int main()
{
    int x,y,w;
    while(~scanf("%d%d%d%d",&n,&m,&V,&st))
    {
        init();
        FOR1(i,n)
        {
            scanf("%d%d",&cost[i],&val[i]);
        }
        FOR1(i,m)
        {
            scanf("%d%d%d",&x,&y,&w);
            add_edge(x,y,w);

        }
        topsort();
        memset(vis,0,sizeof vis);
        vis[st]=1;
        dfs(st);
        DP();
//        work();
//        printf("%d\n",maxi);
        printf("%lld\n",ans);
    }

    return 0;
}
/*
4 4 10 1
1 1
2 3
3 4
4 5
1 2 5
1 3 4
2 4 4
3 4 5


4 4 10 1
1 1
2 1
3 4
4 5
1 2 5
1 3 4
2 4 4
3 4 5
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值