Crazy Shopping(拓扑排序+完全背包)

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.

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 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 ofNitori.

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

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4439

题目大意:从前有n座山,山里都有一座庙,庙里都有一个老和尚,老和尚专送纪念品,每个纪念品重量为cost[i],价值为val[i]。n座山形成一张有m条边的有向图,某山道某某山都有距离dist[i]。主角xx从st点出发,背着个容量为M的背包,想要收集最多的价值。但是主角体弱多病要顾及身体,每次背着重量为wi从某山走到某某山就要耗费dist[i]*wi的能量。最后能价值最多时最少的能量耗费为多少?

解题思路:看上去像神题,但仔细分析就是一个拓扑排序+完全背包,不过细节着实有点蛋痛。我最开始是想先再每个点做一次完全背包,这样转移的时候直接转移就好了。但是这样似乎很难实现。

设dp[i][j]到达i点背包里装容量为j的最大价值,power[i][j]表示价值最大时的最小耗费。按上一段说的一开始就转移的话,那么dp[i][j]都会被更新,此时power[i][j]应该是0,因为不知道前面跑了几万几千里。但是这样并不靠谱,先不说从st能不能到i,就说能到达的时候,我们怎么得到一个和dp[i][j]一样的值,那么此时power应该更新为多少?还有dp[i][j]要怎么更新?

上面是我的一次失败的尝试,但对后面的分析也有帮助,我只要先进行拓扑排序,然后利用拓扑序向后转移,转移到下一个点就做一次完全背包,一个点可能从很多歌点转移来,优先更新dp[i][j]然后更新power[i][j],转移得到的dp[i][j]和power[i][j]都是从前序节点转移而来,如果.而每次转移的时候还必须对下一个节点进行标记,表示能否从st点而来。

具体的转移方程和完全背包很像,只是在价值一样的时候要依据power进行转移,实现见代码。

测试数据:

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
3 5
2 2
3 3
1 1
1 2 5
1 3 10
2 4 4
3 4 5

4 4 15 1
4 7
2 3
3 3
1 1
1 2 5
1 3 10
2 4 0
3 4 5

4 4 0 1
4 7
2 3
3 3
1 1
1 2 5
1 3 10
2 4 0
3 4 5

4 4 15 4
4 7
2 3
3 3
1 1
1 2 5
1 3 10
2 4 0
3 4 5

4 4 15 2
4 7
2 3
3 3
1 1
1 2 5
1 3 10
2 4 0
3 4 5

4 3 15 1
2 3
3 3
2 1
1 1
1 3 0
2 3 5
3 4 0

4 3 15 1
2 3
3 3
2 1
1 1
1 3 0
2 3 5
3 4 10

Output:
15 0
16 81
25 60
0 0
15 0
22 0
22 0
22 140

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define MIN 710
#define MAX 2100
#define mem(a,x) memset((a),(x),sizeof((a)))
int n,m,road,x;
int cost[MIN],val[MIN],flag[MIN];
int st[MIN],top,cnt[MIN],real[MIN],Index;
int dp[MIN][MAX],power[MIN][MAX],ans,dist;
struct node
{
int v,len;
} cur; vector<node> mmap[MIN]; void tuopu()
{
for(int i=; i<=n; i++)
{
if(cnt[i]==)
st[++top]=i;
while(top!=)
{
int v=st[top--];
real[++Index]=v;
int size = mmap[v].size();
for(int j=; j<size; j++)
{
cur=mmap[v][j];
cnt[cur.v]--;
if(cnt[cur.v]==)
st[++top]=cur.v;
}
}
}
}
void Solve_AC()
{ int i,j,k,s,v,size,tp; for (j = ; j <= m; ++j)
{
//相当于初始化
power[x][j] = ;
if (j >= cost[x])
dp[x][j] = max(dp[x][j],dp[x][j-cost[x]]+val[x]);
if (dp[x][j] > ans)
ans = dp[x][j],dist = ;
//printf("%d %lld ans%lld\n",j,dp[x][j],ans);
} flag[x] = ;
for (i = ; i <= n; ++i)
{ v = real[i];
if (flag[v] == ) continue; //flag为0 ,表示不可达
size = mmap[v].size();
for (s = ; s < size; ++s)
{ cur = mmap[v][s];
tp = cur.v,flag[tp] = ; //可达,tp为下一个节点号
for (j = ; j <= m; ++j)
{ if (dp[tp][j] < dp[v][j]) //优先根据dp[tp][j]进行转移
{ dp[tp][j] = dp[v][j];
power[tp][j] = power[v][j] + cur.len * j;
}
else if (dp[tp][j] == dp[v][j]) //当dp[tp][j]和dp[v][j]相等才根据power[i][j]转移
{ if (power[tp][j] == -) //第一次到达tp点
power[tp][j] = power[v][j]+cur.len * j;
else
power[tp][j] = min(power[tp][j],power[v][j] + cur.len * j);
}
//没有这个if就会出现后面的耗费比前面多,但实际获得的价值都一样
if (j && dp[tp][j] == dp[tp][j-])
power[tp][j] = min(power[tp][j],power[tp][j-]);
} for (j = cost[tp]; j <= m; ++j)
{
//完全背包
if (dp[tp][j] < dp[tp][j-cost[tp]]+val[tp])
{ dp[tp][j] = dp[tp][j-cost[tp]] + val[tp];
power[tp][j] = power[tp][j-cost[tp]];
}
else if(dp[tp][j] == dp[tp][j-cost[tp]]+val[tp])
power[tp][j] = min(power[tp][j],power[tp][j-cost[tp]]);
} for (j = ; j <= m; ++j)
{
//更新答案
if (dp[tp][j] > ans)
ans = dp[tp][j],dist = power[tp][j];
else if (dp[tp][j] == ans)
dist = min(dist,power[tp][j]);
}
//printf("cur %d:\n",cur.v),Debug_InPut();
}
}
} int main()
{
int i,j,k,a,b,c;
while(scanf("%d%d%d%d",&n,&road,&m,&x)!=EOF)
{
Index=;
top=ans=dist=;
mem(dp,);
mem(cnt,);
mem(flag,);
mem(power,-);
for(i=; i<=n; i++)
{
mmap[i].clear();
}
for(i=; i<=n; i++)
{
scanf("%d%d",&cost[i],&val[i]);
}
for(i=; i<=road ; i++)
{
scanf("%d%d%d",&a,&b,&c);
cnt[b]++;
cur.v=b;
cur.len=c;
mmap[a].push_back(cur);
}
tuopu();
Solve_AC();
printf("%d\n",dist);
}
return ;
}

》》原文转载《《

Crazy Shopping(拓扑排序+完全背包)的更多相关文章

  1. zoj 3524(拓扑排序+多重背包)(好题)

    http://blog.csdn.net/woshi250hua/article/details/7824773 题目大意:从前有n座山,山里都有一座庙,庙里都有一个老和尚,老和尚专送纪念品,每个纪念 ...

  2. ZOJ-3524 拓扑排序+完全背包(好题)

    题意:在一个DAG上,主角初始有W钱起点在s点,每个点有一个代价wi和价值vi,主角从起点走到某一点不能回头走,一路上可以买东西(一个点的东西可以买无限次),且体力消耗为身上负重*路径长度.主角可以在 ...

  3. E - Ingredients 拓扑排序+01背包

    题源:https://codeforces.com/gym/101635/attachments 题意: n行,每行给定字符串s1,s2,s3代表一些菜谱名.s2和s3是煮成是的必要条件,然后给出c和 ...

  4. ZOJ 3524 Crazy Shopping

    Crazy Shopping Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on ZJU. Original ...

  5. hdoj 4324 Triangle LOVE【拓扑排序判断是否存在环】

    Triangle LOVE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tot ...

  6. 有向图和拓扑排序Java实现

    package practice; import java.util.ArrayDeque; import java.util.Iterator; import java.util.Stack; pu ...

  7. HDU 4324 Triangle LOVE (拓扑排序)

    Triangle LOVE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tot ...

  8. HDU4324 Triangle LOVE【拓扑排序】

    Triangle LOVE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) To ...

  9. 算法与数据结构(七) AOV网的拓扑排序

    今天博客的内容依然与图有关,今天博客的主题是关于拓扑排序的.拓扑排序是基于AOV网的,关于AOV网的概念,我想引用下方这句话来介绍: AOV网:在现代化管理中,人们常用有向图来描述和分析一项工程的计划 ...

随机推荐

  1. 【转】PowerDesigner快捷键

    一般快捷键 快捷键 说明 F4 打开检查模型窗口,检查模型 F5 如果图窗口内的图改变过大小,恢复为原有大小即正常大小 F6 放大图窗口内的图 F7 缩小图窗口内的图 F8 在图窗口内中查看全部图内容 ...

  2. [R]关于R语言的绘图函数

    1. 首先就是plot(x,y,...) 参数: x: 所绘图形横坐标构成的对象 y: 所绘图形纵坐标构成的对象 type: 指定所绘图形类型 pch: 指定绘制点时使用的符号 cex: 指定符号的大 ...

  3. Linux学习笔记-基本操作4

    1. gdb调试2. makefile的编写3. 系统IO函数 1. gdb调试:        1. 启动gdb + 可执行文件        2. 查看代码:                l== ...

  4. 转---30 分钟学会 Flex 布局

    正文从这开始- Flex 基本概念: 在 flex 容器中默认存在两条轴,水平主轴(main axis) 和垂直的交叉轴(cross axis),这是默认的设置,当然你可以通过修改使垂直方向变为主轴, ...

  5. linux服务器的相关信息查看(端口占用,cpu、内存占用,防火墙,系统信息,vim编辑器使用等)

    一.端口占用情况   https://www.cnblogs.com/CEO-H/p/7794306.html (1)查看所有端口.进程的使用情况:netstat -tunlp (2)查看某一端口的使 ...

  6. ping端口是否开放(windows,macos,linux)

    windows中ping端口:tcping命令 1. tcping 非自带命令,首先安装tcping命令,也可以去官网:http://www.elifulkerson.com/projects/tcp ...

  7. iOS-自定义NavigationItem返回按钮【pop返回按钮】

    在用navigationVC时,返回按钮有时候不想用系统的,这里用继承的方式把按钮替换了,同时也可以实现系统的右滑返回,很简单: 1.创建基类 BasePopViewController 创建一个用于 ...

  8. JVM(三)JVM的ClassLoader类加载器

    1.类加载的生命周期 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括: (1)加载 (2)验证 (3)准备 (4)解析 (5)初始化 (6)使用 (7)卸载 一共7个阶段.其中验 ...

  9. 打印页面时a标签不显示URL的方法

    以前写博客啊,总想写一篇大作,然后希望能挂到博客园首页,隔一会儿看看阅读量有多少.其实哪有那么多大作,大部分时间都是解决了一个小问题,然后需要记录一下.比如下面这篇. 今天遇到一个需求是,打印网页时, ...

  10. redis源码学习-dict

    1.字典相关的几个结构体 dict由hash table存储key-value, hash table数组每一个元素存放dictEntry链接的链表头结点,dictEntry节点存放key-value ...