差分约束详解&&锣鼓SCOI2011糖果题解
Posted lbssxz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了差分约束详解&&锣鼓SCOI2011糖果题解相关的知识,希望对你有一定的参考价值。
差分约束系统:
如果一个系统由n个变量和m个约束条件组成,形成m个形如ai-aj≤k的不等式(i,j∈[1,n],k为常数),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。
——度娘。
然而并没有看懂。。
通俗来说,满足差分约束的条件是题目中给了你多个ai-aj<=(>=,<,>之类)的条件,要求同时满足这些条件并求极值的问题。
内么,怎么同时满足这些问题呢?
假如我们以这个东西为例:
a2<a1,a2<a3,a3<a1。并要求同时满足求满足条件的a的和的最小值。(a>=0)
那么,我们可以用图来描述这个问题:
我们设有向边(u,v),边权为1表示u>v。因为u>v等价于u-1>=v,也就是u-v>=1,那么我们就将(u,v),权值i理解为u-v=i。
画出来图长这样:
要满足所有条件且最小,也就是满足a1-a2=1,a1-a3+(a3-a2)=2。
整理得:a1-a2=1;a1-a2=2;
取最大的那个。
在图上表示,就(莫名其妙的)变成了求最长路!
很神奇吧qwq。
也就是说,如果你想满足所有条件,就先建图,然后根据题目情况(最短路求得未知数最大,最长路求得未知数最小)来跑最长/短路。
例题:SCOI2011糖果:
跑最长路qwq:
code:
#include<cstdio> #include<cstring> #include<queue> #include<iostream> #include<cstdlib> using namespace std; int n,k,x,a,b,sum=0,head[200002],cnt[200002],dis[200002]; long long ans=0; queue<int> q; bool vis[200002]; inline int read() int ans=0; char ch=getchar(),last=‘ ‘; while(ch>‘9‘||ch<‘0‘)last=ch,ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘)ans=(ans<<3)+(ans<<1)+ch-‘0‘,ch=getchar(); return last==‘-‘?-ans:ans; struct edge int next,to,dis; edg[210001]; inline void add(int from,int to,int dis) edg[++sum].dis=dis; edg[sum].to=to; edg[sum].next=head[from]; head[from]=sum; int main() n=read();k=read(); for(int i=1;i<=k;i++) x=read(),a=read(),b=read(); if(x==1) add(a,b,0);add(b,a,0); if(x==2) if(a==b) printf("-1");return 0; add(a,b,1); if(x==3) add(b,a,0); if(x==4) if(a==b)cout<<-1;return 0; add(b,a,1); if(x==5) add(a,b,0); for(int i=1;i<=n;i++)add(0,i,1); vis[0]=1;q.push(0); while(!q.empty()) int now=q.front();q.pop();vis[now]=0; if(cnt[now]==n-1) printf("-1");return 0; cnt[now]++; for(int i=head[now];i;i=edg[i].next) int v=edg[i].to; if(dis[v]<dis[now]+edg[i].dis) dis[v]=dis[now]+edg[i].dis; if(!vis[v])vis[v]=1;q.push(v); for(int i=1;i<=n;i++) ans+=dis[i]; printf("%lld\\n",ans);
完结qwq
以上是关于差分约束详解&&锣鼓SCOI2011糖果题解的主要内容,如果未能解决你的问题,请参考以下文章
[luogu2474 SCOI2008]天平(floyd差分约束)