BZOJ2330 糖果[差分约束方案+spfa?/tarjan]
以往对于差分约束理解不是太深,导致这题屡次被坑,在此记录一下细节的理解。
差分约束实际上就是利用了spfa的一个特性:只要有$dis_y>dis_x+w_{x,y}$就松弛,直到所有边关系都满足$dis_y\le dis_x+w_{x,y}$,而这一不等式恰好可以套在差分约束问题里。差分约束要求满足前面这个玩意,把每个变量的值看做$dis_i$,建边,跑spfa最短路,使得所有边都满足关系。这个之前就已经明白了。
但是忽视了一点:注意到跑出来的最短路中$dis$即为$x$的一组合法取值,并且这组取值同时加上某个值$a$,也是满足不等式约束的。不过,这些解集构成的集合,并不是解集集合的全集(有点绕),显然在跑spfa时只是使得每个点的$dis$贴着松弛他的$dis+w$,其实这个实际取值$x$还可以更小。而如果用最长路的建边方式,$x$可以更大。两者都是等效的。在这题里面,由于要求每个数都是正整数且总和最小,并不可以使用建负权边跑最短路的方法。。。因为解出来的解集即使全部平移到正数区域,你也不知道有没有哪些数可以更小一些,哪些数不能再小了。而建正权边跑最长路,根据上述分析,每个$x$也就是$dis$必然是贴着最小的可能取值的,这样就极其简便的获取最小解。
第二个点,因为spfa理论复杂度$O(mn)$,所以想卡很容易,再加上这题由于差分约束要把所有点都加入队列,所以很容易想到如果构造一条链,连边全部反过来,$1\leftarrow 2\leftarrow ...\leftarrow n$,显然会跑接近$n^2$次,不过数据里并没有故意卡,倒是有一个顺着正向的链的data,我这里采用直接顺着加入队列就没有问题了。但是实际上还是可以卡的?另外,有的点明显spfa被卡,但是有数据连了-1的自环,可以提前特判结束。
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<cmath>
- #include<queue>
- #define dbg(x) cerr << #x << " = " << x <<endl
- #define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
- using namespace std;
- typedef long long ll;
- typedef double db;
- typedef pair<int,int> pii;
- template<typename T>inline T _min(T A,T B){return A<B?A:B;}
- template<typename T>inline T _max(T A,T B){return A>B?A:B;}
- template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
- template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
- template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
- template<typename T>inline T read(T&x){
- x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
- while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
- }
- const int N=1e5+;
- struct thxorz{int to,nxt,w;}G[N<<];
- int Head[N],tot,inq[N],rel[N];
- int n,m;
- ll ans;
- inline void Addedge(int x,int y,int z){G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot,G[tot].w=z;}
- queue<int> q;
- ll dis[N];
- #define y G[j].to
- inline bool spfa(){
- for(register int i=;i<=n;++i)q.push(i),inq[i]=,dis[i]=;
- while(!q.empty()){
- int x=q.front();q.pop();inq[x]=;//dbg2(x,dis[x]);
- for(register int j=Head[x];j;j=G[j].nxt)if(MAX(dis[y],dis[x]+G[j].w)){
- rel[y]=rel[x]+;if(rel[y]>=n)return ;
- if(!inq[y])inq[y]=,q.push(y);
- }
- }
- return ;
- }
- #undef y
- int main(){//freopen("1.in","r",stdin);//freopen("test.ans","w",stdout);
- read(n),read(m);
- for(register int i=,opt,x,y;i<=m;++i){
- read(opt),read(x),read(y);
- if(opt==)Addedge(x,y,),Addedge(y,x,);
- else if(opt==)Addedge(x,y,);
- else if(opt==)Addedge(y,x,);
- else if(opt==)Addedge(y,x,);
- else Addedge(x,y,);
- if((opt==||opt==)&&x==y){printf("-1\n");return ;}
- }
- if(spfa()){
- for(register int i=;i<=n;++i)ans+=dis[i];
- printf("%lld\n",ans);
- }
- else puts("-1");
- return ;
- }
2019.11.01UPD:
关于正权图或者负权图的差分约束有更快的线性做法。
以最长路为例,如果图上只有正权边和零边,那么,只要看有没有环是正环,也就是说,对于每一条正边,如果他在一个SCC里,那显然就是正环了,直接判无解。否则,有环的话也只能是零环,零环意味着环上所有点值相同(因为一个被更新,所有点最长路顺着一圈都被更新),所以可以把他们缩掉,这样就变成了一张DAG,这时候就可以直接拓扑排序更新最大值了,最后每个点所在SCC的值就是他的解了。复杂度线性。当然,环上有正有负就不好整了。spfa又死了。
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<cmath>
- #include<queue>
- #define dbg(x) cerr << #x << " = " << x <<endl
- #define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
- using namespace std;
- typedef long long ll;
- typedef double db;
- typedef pair<int,int> pii;
- template<typename T>inline T _min(T A,T B){return A<B?A:B;}
- template<typename T>inline T _max(T A,T B){return A>B?A:B;}
- template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
- template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
- template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
- template<typename T>inline T read(T&x){
- x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
- while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
- }
- const int N=1e5+;
- int n,m;
- ll ans;
- struct thxorz{
- int head[N],nxt[N<<],to[N<<],from[N<<],w[N<<],tot;
- inline void add(int x,int y,int z){to[++tot]=y,from[tot]=x,nxt[tot]=head[x],head[x]=tot,w[tot]=z;}
- }G1,G2;
- int dfn[N],low[N],stk[N],instk[N],bel[N],scc,tim,top;
- #define y G1.to[j]
- void tarjan(int x){
- dfn[x]=low[x]=++tim,stk[++top]=x,instk[x]=;
- for(register int j=G1.head[x];j;j=G1.nxt[j]){
- if(!dfn[y])tarjan(y),MIN(low[x],low[y]);
- else if(instk[y])MIN(low[x],dfn[y]);
- }
- if(low[x]==dfn[x]){
- int tmp;++scc;
- do instk[tmp=stk[top--]]=,bel[tmp]=scc;while(tmp^x);
- }
- }
- #undef y
- queue<int> q;
- int dis[N],deg[N];
- #define y G2.to[j]
- inline void topo(){
- for(register int i=;i<=scc;++i){dis[i]=;if(!deg[i])q.push(i);}
- while(!q.empty()){
- int x=q.front();q.pop();
- for(register int j=G2.head[x];j;j=G2.nxt[j]){
- MAX(dis[y],dis[x]+G2.w[j]);
- if(!(--deg[y]))q.push(y);
- }
- }
- }
- #undef y
- int main(){//freopen("1.in","r",stdin);//freopen("test.ans","w",stdout);
- read(n),read(m);
- for(register int i=,opt,x,y;i<=m;++i){
- read(opt),read(x),read(y);
- if(opt==)G1.add(x,y,),G1.add(y,x,);
- else if(opt==)G1.add(x,y,);
- else if(opt==)G1.add(y,x,);
- else if(opt==)G1.add(y,x,);
- else G1.add(x,y,);
- }
- for(register int i=;i<=n;++i)if(!dfn[i])tarjan(i);
- for(register int t=;t<=G1.tot;++t){
- int x=G1.from[t],y=G1.to[t];
- if(bel[x]==bel[y]&&G1.w[t]){puts("-1");return ;}
- else if(bel[x]^bel[y])G2.add(bel[x],bel[y],G1.w[t]),++deg[bel[y]];
- }
- topo();
- for(register int i=;i<=n;++i)ans+=dis[bel[i]];
- printf("%lld\n",ans);
- return ;
- }
tarjan!
BZOJ2330 糖果[差分约束方案+spfa?/tarjan]的更多相关文章
- bzoj2330糖果——差分约束
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2330 差分约束,再建立一个源点0,向所有点连边权为1的边,表示每个人都会分到糖果: 答案较大 ...
- 【BZOJ2330】【SDOI2012】糖果(差分约束,SPFA)
[BZOJ2330][SDOI2012]糖果 题面 题目描述 幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些要 ...
- BZOJ2330:[SCOI2011]糖果(差分约束)
Description 幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的 ...
- bzoj2330(差分约束)
题解:这道题是练差分约束的一道好题目吧,我具体在代码中注释,这样更加好理解, 为什么求最长路呢?因为这样保证了满足条件,如果存在正权环,就表示无解,就是 正权环之间不断要更多的糖果才行. #inclu ...
- P3275 [SCOI2011]糖果 && 差分约束(二)
学习完了差分约束是否有解, 现在我们学习求解最大解和最小解 首先我们回想一下是否有解的求解过程, 不难发现最后跑出来任意两点的最短路关系即为这两元素的最短路关系. 即: 最后的最短路蕴含了所有元素之间 ...
- BZOJ 2330 SCOI2011糖果 差分约束
2330: [SCOI2011]糖果 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2819 Solved: 820 题目连接 http://www ...
- bzoj 2330 [SCOI2011]糖果 差分约束模板
题目大意 幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配 ...
- 洛谷P3275 [SCOI2011]糖果(差分约束)
题目描述 幼儿园里有 $N$ 个小朋友,$lxhgww $老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的 ...
- POJ 2983 Is the Information Reliable? 信息可靠吗 (差分约束,spfa)
题意:有n个站排成一列,针对每个站的位置与距离关系,现有多个约束条件,约束条件分两种:(1)确定的.明确说明站a距离站b多少个单位距离.(2)不确定的.只知道a在b的左边至少1个单位距离. 根据已知 ...
随机推荐
- 解决 ThinkPHP 5 把控制器下的文件夹当做控制器输出的问题
目录结构: application/home/controller/user_info/User.php 输入路由:/home/user_info/user/index 看样子没毛病,但会报错: 这是 ...
- 浅谈 OpenResty,基于opebresty+redis进行实时线上限流
一.前言 我们都知道Nginx有很多的特性和好处,但是在Nginx上开发成了一个难题,Nginx模块需要用C开发,而且必须符合一系列复杂的规则,最重要的用C开发模块必须要熟悉Nginx的源代码,使得开 ...
- struts框架之环境搭建(一)
一.首先,我们需要做一些准备工作: 1.1. 下载struts:https://struts.apache.org/download.cgi#struts2520 1.2. 下载tomcat:ht ...
- FileSystemResource 找不到文件
环境 Spring 3.2.5.RELEASE 原因 使用 FileSystemResource 加载文件的过程中,发现一个奇怪的现象,路径完全正确,但是找不到文件的情况.可能的原因是文件的路径上有压 ...
- 首篇-记录自己学习python之路!
对于自己学习python的目的比较明确——爬虫和量化. 目前找了一些资源进行学习,先进行量化方面的学习,爬虫滞后.目前的目标是“180天掌握尽可能多的量化能力”! 以后定时发送自己学习思考内容以作自己 ...
- 一次生产的JVM优化
背景 生产环境有二台阿里云服务器,均为同一时期购买的,CPU.内存.硬盘等配置相同.具体配置如下: 节点 CPU 内存 硬盘 其它 A 2CPU 4G 普通云盘 Centos6.4 64位+JDK1. ...
- 怎样理解 DOCTYPE 声明
1. HTML 4.01 Strict <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www. ...
- 《深入实践C++模板编程》之四——特例
1. 所谓模板特例,是针对符合某种条件的模板参数值集合另外声明的模板实现变体. template<typename T> class my_vector; template<> ...
- wcf可以返回的类型有哪些
Windows Communication Foundation (WCF) 使用 DataContractSerializer 作为其默认的序列化引擎以将数据转换到 XML 并将 XML 转换回数据 ...
- json字符串对象
1.将字符串转为json对象:JSON.parse(); 2.json对象转字符串:JSON.stringify(); <!DOCTYPE html> <html> <h ...