题意:

有n种商品,每种商品有一个价格 p[i] 。

每种商品都有2种打折方式:

1. 给你优惠 d[i] 元。

2. 免费送你第 f[i] 种饮料。

现在求每种饮料至少一瓶的最小花费。

dp[i][0] 表示 i 的子树内所有的饮料都至少买了一瓶。

dp[i][1] 表示 i 的子树内所有的饮料都至少买了一瓶 且 第i种饮料是使用第2种方式购买的。

我们考虑树的转移方式。

sum[i] 表示  dp[son[i]][0] 的和

dp[i][1] = sum[i] + p[i]

dp[i][0] = min(p[i]-d[i]+sum[i], sum[i] - dp[son[i][0] + dp[son[i][1] )

然后我们可以先把环都抠出来, 然后将环上的边都标记一下,

然后先把环的子树都转移到环上来, 最后再处理环的问题。

假设一个环为 a -> b -> c ->  d  -> a ,mn 为这个环的最小花费。

我们断开a -> b 这条边,并且 b 不是 通过 a 送来的。

G[0][0] = dp[b][0] G[0][1] = dp[b][1]

路上转移的状态为 G[1][1] = dp[c][1] + G[0][0];

G[1][0] = min(G[0][1]+sum[c], dp[c][0] + G[0][0])

这样一直转移到G[3][0]

因为我们规定b 不是 通过 a 送来的。 mn = min(mn, G[3][0])

然后我们假设 b 是通过 a 送过来的

G[0][0] = sum[b]    G[0][1] = dp[b][1]

然后通过上面的转移方程转移到G[3][1]。

因为b是a送的 那么 a 必须要按方式1购买 所以 mn = min(mn, G[3][1])

最后将 mn 加入答案中。

然后 跑完所有环之后 就能得到答案了。

 #include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
int p[N], d[N], f[N];
int head[N], to[N], nt[N];
int vis[N];
int cntCir = , tot = , top, n;
int sta[N];
vector<int> cir[N];
int vvis[N];
LL dp[N][];
LL sum[N];
LL G[N][];
void add(int u, int v){
to[tot] = v;
nt[tot] = head[u];
head[u] = tot++;
}
void getCir(int u){
if(vis[u] == ) return ;
if(vis[u] == -){
cntCir++;
for(int i = top; i >= ; i--){
cir[cntCir].pb(sta[i]);
vvis[sta[i]] = ;
if(sta[i] == u) break;
}
return;
}
vis[u] = -;
sta[++top] = u;
getCir(f[u]);
top--;
vis[u] = ;
}
void dfs(int u){
for(int i = head[u]; ~i; i = nt[i]){
if(vvis[to[i]]) continue;
dfs(to[i]);
sum[u] += dp[to[i]][];
}
dp[u][] = sum[u] + p[u];
dp[u][] = sum[u] + p[u] - d[u];
for(int i = head[u]; ~i; i = nt[i]){
if(vvis[to[i]]) continue;
dp[u][] = min(dp[u][], sum[u] - dp[to[i]][] + dp[to[i]][]);
}
}
int main(){
memset(head, -, sizeof(head));
scanf("%d", &n);
for(int i = ; i <= n; i++) scanf("%d", &p[i]);
for(int i = ; i <= n; i++) scanf("%d", &d[i]);
for(int i = ; i <= n; i++) {
scanf("%d", &f[i]);
add(f[i], i);
}
for(int i = ; i <= n; i++){
if(!vis[i]){
top = ;
getCir(i);
}
}
LL ans = ;
for(int i = ; i <= cntCir; i++){
reverse(cir[i].begin(), cir[i].end());
for(int j = ; j < cir[i].size(); j++){
dfs(cir[i][j]);
}
LL mn = INF;
G[][] = dp[cir[i][]][];
G[][] = dp[cir[i][]][];
for(int j = ; j < cir[i].size(); j++){
G[j][] = G[j-][] + dp[cir[i][j]][];
G[j][] = min(G[j-][]+sum[cir[i][j]], dp[cir[i][j]][]+G[j-][]);
}
mn = min(mn, G[cir[i].size()-][]);
G[][] = sum[cir[i][]];
G[][] = dp[cir[i][]][];
for(int j = ; j < cir[i].size(); j++){
G[j][] = G[j-][] + dp[cir[i][j]][];
G[j][] = min(G[j-][]+sum[cir[i][j]], dp[cir[i][j]][]+G[j-][]);
}
mn = min(mn, G[cir[i].size()-][]);
ans += mn;
}
printf("%lld\n", ans);
return ;
}

最新文章

  1. [转]EL表达式和JSTL表达式实例
  2. 使用robot frame selenium中遇到的问题汇总
  3. KMS服务器激活Windows和Office2013EnterprisePlus
  4. Lua标准库- 模块(Modules)
  5. PHP+memcache扩展(集成环境wampserver环境下)
  6. Section 1.4 Mother&#39;s Milk
  7. 用CSS3制作的旋转六面体动画
  8. 算法:最大子数组own
  9. 接入淘宝SDK(OneSDK)和支付宝SDK(AlipaySDK)出现 duplicate symbols for architecture i386
  10. IOS 通过button获取cell
  11. 小言C指针
  12. python 私有方法
  13. 使用easyui搭建网页架子
  14. Oracle PGA作用&amp;work_mode
  15. java学习--异常
  16. C# 实现Bresenham算法(vs2010)
  17. js实现获取两个日期之间所有日期最简单的方法
  18. mac_os_x更新yosemite以后github客户端更新提示ca认证错误解决办法
  19. 03 Maven 坐标与依赖
  20. vs中插件影响代码自动创建后台事件问题

热门文章

  1. python编码问题——解决python3 UnicodeEncodeError: &#39;gbk&#39; codec can&#39;t encode character &#39;\xXX&#39; in position XX
  2. WIN10安装VC6.0无法使用的解决办法
  3. mysql中left join right join inner join用法分析
  4. Unity经典游戏教程之:是男人就下100层
  5. Web项目如何做单元测试
  6. java-极光推送教程
  7. python3学习-lxml模块
  8. OpenResty 社区王院生:APISIX 的高性能实践
  9. 由group by引发的sql_mode的学习
  10. vue-cli报错:Class constructor FileManager cannot be invoked without &#39;new&#39;