[JSOI2008]小店购物 & bzoj4349:最小树形图 最小树形图
其实是同一道题,,,样例都一模一样
题解:
一开始看想了好久,,,还想到了最短路和最小生成树,,然而写的时候才意识到最小生成树应该要用无向边
其实这题是最小树形图
细节还是挺多了,,,感觉做了一天,,,,
表示做得有点失智,不想码字了,这里就放上我代码里的注释吧,
一些小细节和易错点代码里面也有详细注释,注意看error标注的地方就好了,
具体操作也有很多注释,,,(没错我就是一个喜欢打注释的人)
注意到一件事:优惠政策与买的件数无关,也就是说不管买了多少,只要买了就可以优惠,
这就意味着构造最小树形图的时候边权应该按照1的来算,因为如果要购买多件的话,可以等到最后
已经买完了所有物品再用最低价购买(肯定可以达到最低价格),
因为第一次购买的时候是不允许出现环的,(不然的话先购买哪个?肯定有个先后顺序的啊)
但是后来买就无所谓了,因为东西反正都买了,就比如说买a再买b可以优惠5元,买b再买a可以优惠10元,
这个时候显然先买b再买a,但我们可以只买一个b,这样的话买完a和b后再购买剩下的b时就可以每件优惠5元了
1,确定一个根(建立超级源点)
2,找到除根外每一个点的最小入边,若这些边构成了环(此时必然不联通),则缩环成点,并将环内的每一个点的其他入边都减去环内的入边,
3,重复步骤2直到没有环出现(构成了树)。
或者说不用bool记录有没有被访问,而是用vis记录访问它的是谁,因为不能被同一个点多次访问,但被多个点一次访问是合法的
放上自认为很好看的代码
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 60
#define ac 10000
int n, m, s, tot, cnt, tmp;
int last[AC], id[AC], buy[AC], vis[AC];
int Stack[AC], top;//栈,辅助找环
double ans;
double in[AC]; struct road{
int x,y;double Size;
}way[ac];
/*注意到一件事:优惠政策与买的件数无关,也就是说不管买了多少,只要买了就可以优惠,
这就意味着构造最小树形图的时候边权应该按照1的来算,因为如果要购买多件的话,可以等到最后
已经买完了所有物品再用最低价购买(肯定可以达到最低价格),
因为第一次购买的时候是不允许出现环的,(不然的话先购买哪个?肯定有个先后顺序的啊)
但是后来买就无所谓了,因为东西反正都买了,就比如说买a再买b可以优惠5元,买b再买a可以优惠10元,
这个时候显然先买b再买a,但我们可以只买一个b,这样的话买完a和b后再购买剩下的b时就可以每件优惠5元了
1,确定一个根(建立超级源点)
2,找到除根外每一个点的最小入边,若这些边构成了环(此时必然不联通),则缩环成点,并将环内的每一个点的其他入边都减去环内的入边,
3,重复步骤2直到没有环出现(构成了树)。 因为边很少,所以只能形成一个很简单的环,又因为s没有入度,所以s不可能出现在环内,
所以说可以从s出发dfs一遍,如果有点没被访问到就是有环???? 或者说不用bool记录有没有被访问,而是用vis记录访问它的是谁,因为不能被同一个点多次访问,
但被多个点一次访问是合法的
*/ inline void upmin(double &a,double b)
{
if(b < a) a = b;
} void pre()
{
double a;int b,c;
scanf("%d", &n);
memset(in, , sizeof(in));//原来127是很大的?
s = n + ;
for(R i = ; i <= n; i++)
{
scanf("%lf%d", &a, &buy[++tot]);
if(!buy[tot])
{
--tot;
continue;
}
--buy[tot];//因为第一个是在建树的时候买的
id[i] = tot;//防止不用买的商品占位置
way[++cnt] = (road){s, tot, a};
upmin(in[tot], a);//找到最低价
}
scanf("%d", &m);
for(R i = ; i <= m; i++)
{
scanf("%d%d%lf", &b, &c, &a);
if(!id[b] || !id[c]) continue;
way[++cnt] = (road){id[b], id[c], a};
upmin(in[id[c]], a);//获取最低价格
}
} void init()
{
for(R i=;i<=tot;i++)//因为每次标号都要重置,所以现在赶紧加上贡献
if(buy[i]) ans += in[i] * (double)buy[i];//直接枚举标号
} void find()//找环
{//error!!!虽然说都是简单环,但是这并不妨碍环有出边,,,,因此还要判断不要误入之前进过的环了
int x;
for(R i = ; i <= tot; i++)//直接枚举标号
{
top = ;
ans += in[x = i];//获取新最小边贡献 + 顺便赋值
if(id[x]) continue;//如果已经被发现在环内就加上贡献走人
while()//找环
{
if(vis[x] == i || x == s || id[x]) break;//error!!!不要误入之前进过的环了(id[x])
vis[x] = i;
Stack[++top] = x;//存入栈
x = last[x];
}
if(x == i && !id[x])//如果终点被多次访问,error!!!之前进过的环就别去了(id[x])
{//error!!!应该是起点被多次访问,而不是终点,回到起点才是一个环,不然一个环的外向边可能会导致有别的点“误入”环内
++tmp;
while(x = Stack[top--]) id[x] = tmp;//给环内所有节点都赋上同一个编码
}
}
} void get_in()//找最短边 & 前驱
{
int x;
memset(in, , sizeof(in));//重置最短边
for(R i = ; i <= cnt; i++)//直接枚举边,这样更省时
{
x = way[i].y;//存下目标点
if(way[i].x == x) continue;//如果在一个点里那就算了
if(way[i].Size < in[x])
{
last[x] = way[i].x;
in[x] = way[i].Size;//更新最短边
}
}
} void work()
{
while()
{
get_in();
memset(id, , sizeof(id));//重置标号
memset(vis, , sizeof(vis));//重置访问标记
id[s] = s, tmp = ;//重置标号计数,error!!!注意id[s]永远是s
find();
if(!tmp)//如果没有找到环就退出
{
printf("%.2lf\n",ans);
return ;
}
for(R i = ; i <= tot; i++)
if(!id[i]) id[i] = ++tmp;//如果还没有编号,就统一编号
tot = tmp;
for(R i = ; i <= cnt; i++)//每次都更新所有边的所有信息
{
way[i].Size -= in[way[i].y];//权值减去入边的最小边权值
way[i].x = id[way[i].x];//赋为新点
way[i].y = id[way[i].y];
}
}
} int main()
{
freopen("in.in","r",stdin);
pre();
init();
work();
fclose(stdin);
return ;
}
[JSOI2008]小店购物 & bzoj4349:最小树形图 最小树形图的更多相关文章
- Luogu2792 [JSOI2008]小店购物
Luogu2792 [JSOI2008]小店购物 重题 bzoj4349 最小树形图 有 \(n\) 个物品,每个物品有价格 \(c_i\) 和所需个数 \(k_i\) ,所有物品必须恰好买 \(k_ ...
- 【LuoguP2792 】[JSOI2008]小店购物(最小树形图)
题目链接 题目描述 小店的优惠方案十分简单有趣: 一次消费过程中,如您在本店购买了精制油的话,您购买香皂时就可以享受2.00元/块的优惠价:如果您在本店购买了香皂的话,您购买可乐时就可以享受1.50元 ...
- JSOI2008 小店购物
https://www.luogu.org/problem/show?pid=2792 题目背景 JSOI集训队的队员发现,在他们经常活动的集训地,有一个小店因为其丰富的经营优惠方案深受附近居民的青睐 ...
- Luogu2792 JSOI2008 小店购物 最小树形图
传送门 被题意杀 本以为一个种类的物品一定要一起买 看了题解才知道可以先把所有要买的物品买一个,剩下要买的物品就可以得到这个种类的物品能够得到的最大优惠-- 所以现在只需要知道:第一次买所有物品一遍时 ...
- 最小树形图--朱刘算法([JSOI2008]小店购物)
题面 luogu Sol 首先设一个 \(0\) 号点,向所有点连边,表示初始价值 显然这个图的一个 \(0\) 为根的最小有向生成树的边权和就是每个买一次的最小价值 再买就一定能优惠(包含 \(0\ ...
- 洛谷P2792 [JSOI2008]小店购物(最小树形图)
题意 题目链接 Sol 一开始的思路:新建一个虚点向每个点连边,再加上题面中给出的边,边权均为大小*需要购买的数量 然后发现死活都过不去 看了题解才发现题目中有个细节--买了\(A\)就可以买\(B\ ...
- vue+uni-app商城实战 | 第一篇:【有来小店】微信小程序快速开发接入Spring Cloud OAuth2认证中心完成授权登录
一. 前言 本篇通过实战来讲述如何使用uni-app快速进行商城微信小程序的开发以及小程序如何接入后台Spring Cloud微服务. 有来商城 youlai-mall 项目是一套全栈商城系统,技术栈 ...
- C#开发微信门户及应用(24)-微信小店货架信息管理
在前面微信小店系列篇<C#开发微信门户及应用(22)-微信小店的开发和使用>里面介绍了一些微信小店的基础知识,以及<C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试& ...
- C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试
在上篇<C#开发微信门户及应用(22)-微信小店的开发和使用>里面介绍了一些微信小店的基础知识,以及对应的对象模型,本篇继续微信小店的主题,介绍其中API接口的封装和测试使用.微信小店的相 ...
随机推荐
- 「日常训练」Queue(Codeforces Round 303 Div.2 D)
简单到让人不敢相信是D题,但是还是疏忽了一点. 题意与分析 (Codeforces 545D) 题意:n人排队,当一个人排队的时间超过他需要服务的时间就会厌烦,现在要求一个最优排列使得厌烦的人最少. ...
- 「日常训练」 Yukari's Birthday(ZOJ-3665)
题意与分析 二分题.考虑到n的范围是\(10^{12}\),注意到等比公式\(S=a_1\frac{1-q^n}{1-q} (q\ne 1)\),可以看出,不论q有多大(1除外,这个时候\(r=1,k ...
- OSG-粒子系统和初步
本文转至http://www.cnblogs.com/shapherd/archive/2010/08/10/osg.html 作者写的比较好,再次收藏,希望更多的人可以看到这个文章 互联网是是一个相 ...
- RabbitMQ基础教程之使用进阶篇
RabbitMQ基础教程之使用进阶篇 相关博文,推荐查看: RabbitMq基础教程之安装与测试 RabbitMq基础教程之基本概念 RabbitMQ基础教程之基本使用篇 I. 背景 前一篇基本使用篇 ...
- RAP2环境搭建整理(超详细)
RAP2是阿里开源的接口管理平台,最近搭建了一下,将部署文档整理如下: 如果途中遇坑会在文章末尾记录下来嘻嘻 首先,确定环境是否部署好. RAP2所需的环境为: node.js 8.9.4+ mysq ...
- 关于maven项目中修改的JS不生效的解决方案
1. 问题描述 昨天下午博主在开发学习的过程中,碰到一个修改了JS无法生效的问题,折腾我不少的时间,现将百度到的解决方案总结一下,以便下次碰到类似问题能够最快的找到解决方案 2 解决方案 2.1 方案 ...
- 为什么说session依赖cookie,以及cookie的常用知识
session的用法 session在Flask中通常用做设置某些页面的权限,比如某些页面必须要登录才可以看到,登录的信息或标志就放到session中.它的使用过程如下: 在整个flask工程的启动文 ...
- TW实习日记:第22天
今天开发项目的还没完成的功能点,没什么难的,样式复制粘贴,JSON表单配一配,接口调一调,基本就完成了.不过中间在写后台的一些接口时,发现被自己之前写的一些方法给坑了.为什么这样说呢,因为在之前的几个 ...
- fastCMS八大核心对象
fastCMS内置system对象,该对象包含八大核心对象,应用于不同的操作场景,分别是: 1.system.string 对象(处理字符类操作) 2.system.number 对象(处理数字类操作 ...
- 【RL系列】Multi-Armed Bandit笔记补充(一)
在此之前,请先阅读上一篇文章:[RL系列]Multi-Armed Bandit笔记 本篇的主题就如标题所示,只是上一篇文章的补充,主要关注两道来自于Reinforcement Learning: An ...