差分约束系统详解 BZOJ 2330 糖果
2016-06-07 23:01
351 查看
差分约束系统
有一个男人他是这样说的我们有如下几个式子:
A-B<=x —-> A最多比B大x
A-C<=y —-> A最多比C大y
B-C<=z —-> B最多比C大z
所有的约束条件反映了一个问题:
一个数不可能过大,因为某个数可能至多比某个数大k,所以这是一类有最大值问题。
那么假如对于A-B<=x ,我们由B向A连一条大小为x的边。
对于所有等式,由C向B连一条z的边,B向A连一条x的边,C向A连一条y的边。
我们看一下,C到A的路径有两条,一条长度为y的代表A至多比C大y。
另一条路径C–>B–>A的长度为x+z,代表A至多比C大x+z。
最后我们发现C到A的最短路径就是C至多比A大多少,即有最大值限制。
跑SPFA求最短路,记得判断负权回路。
可是另一个男人他是这样说的
A-B>=x —-> A至少比B大x
A-C>=0 —-> A至少和C相等
B-C>=0,C-B>=0 —-> B的值等于C的值
所有的约束条件也反映了一个问题:
一个数不可能过小,因为某个数至少要比某个数大,所以这是一类有最小值问题。
我们对于A-B>=x,我们由B向A连一条大小为x的边。
我们从B走向A的最长(若有正环代表循环约束约束失败)路径就是A至少比B大多少。
我们跑SPFA最长路径,记得判断正环。
对于BZOJ2330我们发现它是第二类问题
我们首先创造出一个0号节点指向每个节点大小为1代表每个小朋友至少分一个。
然后五个式子都可以化简成A-B>=X或B-A>=X,然后跑一下即可。
这题不用int会超,所以注意这句话:typedef int ll;开始其实代的long long……
还有0向n个小盆友的边要从大(n)到小(1)连,否则超时,大爷告诉我的……
@PoPoQQQ,还好告诉我了要不得T一晚上!?F:>:@??>!:”>LE:>@!!
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<cmath> #include<queue> #include<vector> #include<climits> #include<string> #include<cstdlib> #include<set> #include<stack> #include<map> #include<bitset> #include<ctime> using namespace std; typedef int ll; typedef unsigned long long ull; inline ll read() { char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar()); ll x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0'; if(k=='-')x=0-x;return x; } struct E{ ll next; ll zhi; ll s; }e[400500]; ll last[100500]; ll n,m,w; ll dis[100500]; ll vis[100500]; ll pan[100500]; long long ans; queue<ll>q; bool spfa() { q.push(0); ++vis[0]; pan[0]=1; while(!q.empty()) { ll d=q.front(); q.pop(); pan[d]=0; for(int j=last[d];j;j=e[j].zhi) { ll z=e[j].next; if(dis[z]<dis[d]+e[j].s) { dis[z]=dis[d]+e[j].s; ++vis[z]; if(vis[z]>(n+1)) return 0; if(pan[z]==0) { q.push(z); pan[z]=1; } } } } return 1; } void Add(ll a,ll b,ll s) { e[++w].next=b; e[w].s=s; e[w].zhi=last[a]; last[a]=w; return; } int main() { n=read(),m=read(); for(int i=1;i<=m;++i) { ll x=read(),a=read(),b=read(); switch(x) { case 1: Add(a,b,0); Add(b,a,0); break; case 4: swap(a,b); case 2: Add(a,b,1); break; case 3: swap(a,b); case 5: Add(a,b,0); break; } } for(int i=n;i>=1;--i) Add(0,i,1); if(!spfa()) cout<<-1<<endl; else { for(int i=1;i<=n;++i) {ans+=dis[i];} cout<<ans<<endl; } return 0; }
相关文章推荐
- 如何组织构建多文件 C 语言程序(二)
- 如何写好 C main 函数
- Lua和C语言的交互详解
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- C语言编程中统计输入的行数以及单词个数的方法
- C语言自动生成enum值和名字映射代码
- C语言练习题:自由落体的小球简单实例
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法
- C语言实现顺序表基本操作汇总
- C语言中进制知识汇总
- C语言判断一个数是否是2的幂次方或4的幂次方
- C语言中计算正弦的相关函数总结
- 使用C语言详解霍夫曼树数据结构
- C语言实现选择排序、冒泡排序和快速排序的代码示例