题意: 给定n个点(点权未知)和m条信息:u的权值>=v的权值+w 求点权的极小解和极大解(无解则输出-1)

极小解即每个点的点权可能的最小值 极大解即每个点的点权可能的最大值

题解: 差分约束系统

对于val[u]>=val[v]+w 要得到极小解,v是没有受限制的,其最小值为0 而u受到v的限制,显然,val[u]的最小值就是val[v]+w

在多条件限制下,我们用v连向u边权为w的边表示每个限制条件val[u]>=val[v]+w 那么如果得到的是拓扑图,则按拓扑序求到每个点的最长路,就得到极小解

如果得到的不是拓扑图,即图中存在回路 那么如果存在回路边权和>0,则无解(成立的前提是边权都是大于等于零的)

总的来说,求极小解的做法就是,先对val[u]>=val[v]+w建立v连向u边权为w的边 对得到的图求强连通分量,将每个强连通分量缩成一个点 若存在边权和>0的强连通分量,则无解

否则在缩点后的拓扑图上,从入度为0的点出发按拓扑序求到每个点的最长路 该最长路就是每个点的最小值

不缩点直接判是否有回路,没有回路再拓扑,这样做会出错 因为会有边权和为0的强连通分量

对于求极大解,则将条件写成val[v]<=val[u]-w的形式 建立u连向v边权为-w的边,同样求强连通分量并缩点 在缩点后的拓扑图上做最短路,该最短路就是每个点的最大值

差分约束系统如果要求最优解而非合法解,并且整个图不能转化成从某个特定点出发的话。需要进行缩点+拓扑排序……往往只在边权都大于零或者都小于零的时候才成立。

因为对于多起点的情况而言,spfa判负环是失效的,互相制约的关系也很难通过添加虚拟结点来弥补。

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int us[1000010],vs[1000010],ws[1000010];
struct Edge{
int v,w;
};
vector<Edge>G[100010];
vector<int>rG[100010],tv;
bool used[100010];
int cmp[100010];
int ru[100010],f[100010],ansa[100010];
int n,m;
void AddEdge(int U,int V,int W){
G[U].push_back((Edge){V,W});
rG[V].push_back(U);
}
void dfs(int U){
used[U]=1;
for(int i=0;i<G[U].size();++i){
if(!used[G[U][i].v]){
dfs(G[U][i].v);
}
}
tv.push_back(U);
}
void rdfs(int U,int K){
used[U]=1;
cmp[U]=K;
for(int i=0;i<rG[U].size();++i){
if(!used[rG[U][i]]){
rdfs(rG[U][i],K);
}
}
}
int scc(){
memset(used,0,sizeof(used));
tv.clear();
for(int i=1;i<=n;++i){
if(!used[i]){
dfs(i);
}
}
memset(used,0,sizeof(used));
int K=0;
for(int i=tv.size()-1;i>=0;--i){
if(!used[tv[i]]){
rdfs(tv[i],++K);
}
}
return K;
}
int main(){
int x,y,z;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
scanf("%d%d%d",&us[i],&vs[i],&ws[i]);
AddEdge(vs[i],us[i],ws[i]);
}
int sccs=scc();
for(int i=1;i<=m;++i){
if(cmp[vs[i]]==cmp[us[i]] && ws[i]>0){
puts("-1");
return 0;
}
}
for(int i=1;i<=n;++i){
G[i].clear();
}
for(int i=1;i<=m;++i){
if(cmp[vs[i]]!=cmp[us[i]]){
++ru[cmp[us[i]]];
G[cmp[vs[i]]].push_back((Edge){cmp[us[i]],ws[i]});
}
}
queue<int>q;
for(int i=1;i<=sccs;++i){
if(!ru[i]){
q.push(i);
}
}
while(!q.empty()){
int U=q.front(); q.pop();
for(int i=0;i<G[U].size();++i){
f[G[U][i].v]=max(f[G[U][i].v],f[U]+G[U][i].w);
--ru[G[U][i].v];
if(!ru[G[U][i].v]){
q.push(G[U][i].v);
}
}
}
if(*max_element(f+1,f+sccs+1)>100){
puts("-1");
return 0;
}
for(int i=1;i<=n;++i){
ansa[i]=f[cmp[i]];
} for(int i=1;i<=n;++i){
G[i].clear();
rG[i].clear();
}
for(int i=1;i<=m;++i){
AddEdge(us[i],vs[i],-ws[i]);
}
sccs=scc();
for(int i=1;i<=m;++i){
if(cmp[us[i]]==cmp[vs[i]] && ws[i]<0){
puts("-1");
return 0;
}
}
for(int i=1;i<=n;++i){
G[i].clear();
}
for(int i=1;i<=m;++i){
if(cmp[us[i]]!=cmp[vs[i]]){
++ru[cmp[vs[i]]];
G[cmp[us[i]]].push_back((Edge){cmp[vs[i]],-ws[i]});
}
}
memset(f,0x7f,sizeof(f));
for(int i=1;i<=sccs;++i){
if(!ru[i]){
q.push(i);
f[i]=100;
}
}
while(!q.empty()){
int U=q.front(); q.pop();
for(int i=0;i<G[U].size();++i){
f[G[U][i].v]=min(f[G[U][i].v],f[U]+G[U][i].w);
--ru[G[U][i].v];
if(!ru[G[U][i].v]){
q.push(G[U][i].v);
}
}
}
if(*min_element(f+1,f+sccs+1)<0){
puts("-1");
return 0;
}
for(int i=1;i<=n;++i){
printf("%d %d\n",ansa[i],f[cmp[i]]);
}
return 0;
}

【差分约束系统】【强连通分量缩点】【拓扑排序】【DAG最短路】CDOJ1638 红藕香残玉簟秋,轻解罗裳,独上兰舟。的更多相关文章

  1. POJ2762 Going from u to v or from v to u?(判定单连通图:强连通分量+缩点+拓扑排序)

    这道题要判断一张有向图是否是单连通图,即图中是否任意两点u和v都存在u到v或v到u的路径. 方法是,找出图中所有强连通分量,强连通分量上的点肯定也是满足单连通性的,然后对强连通分量进行缩点,缩点后就变 ...

  2. POJ 2762 Going from u to v or from v to u? (强连通分量缩点+拓扑排序)

    题目链接:http://poj.org/problem?id=2762 题意是 有t组样例,n个点m条有向边,取任意两个点u和v,问u能不能到v 或者v能不能到u,要是可以就输出Yes,否则输出No. ...

  3. POJ2762 Going from u to v or from v to u? 强连通分量缩点+拓扑排序

    题目链接:https://vjudge.net/contest/295959#problem/I 或者 http://poj.org/problem?id=2762 题意:输入多组样例,输入n个点和m ...

  4. poj 2762 Going from u to v or from v to u?【强连通分量缩点+拓扑排序】

    Going from u to v or from v to u? Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15812 ...

  5. FFF at Valentine(强连通分量缩点+拓扑排序)

    FFF at Valentine Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  6. BZOJ 1924 所驼门王的宝藏(强连通分量缩点+DAG最长链)

    思路不是很难,因为宝藏只会在给出的n个点内有,于是只需要在这n个点里面连边,一个点如果能到达另一个点则连一条有向边, 这样用强连通分量缩点后答案就是DAG的最长链. 问题在于暴力建图是O(n^2)的, ...

  7. poj 2762 Going from u to v or from v to u?(强连通分量+缩点重构图+拓扑排序)

    http://poj.org/problem?id=2762 Going from u to v or from v to u? Time Limit: 2000MS   Memory Limit:  ...

  8. 【强连通分量缩点】【拓扑排序】【dp预处理】CDOJ1640 花自飘零水自流,一种相思,两处闲愁。

    题意: 在n个点m条边的有向图上,从1出发的回路最多经过多少个不同的点 可以在一条边上逆行一次 题解: 在同一个强连通分量中,显然可以经过当中的每一个点 因此先将强连通分量缩点,点权为强连通分量的点数 ...

  9. tarjan算法(强连通分量 + 强连通分量缩点 + 桥(割边) + 割点 + LCA)

    这篇文章是从网络上总结各方经验 以及 自己找的一些例题的算法模板,主要是用于自己的日后的模板总结以后防失忆常看看的, 写的也是自己能看懂即可. tarjan算法的功能很强大, 可以用来求解强连通分量, ...

随机推荐

  1. 特征工程(Feature Engineering)

    一.什么是特征工程? "Feature engineering is the process of transforming raw data into features that bett ...

  2. Linux 删除带有特殊字符的文件

    Linux 删除带有特殊字符的文件 http://www.cnblogs.com/tester-hehehe/p/5715128.html

  3. 2017多校第6场 HDU 6105 Gameia 博弈

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6105 题意:Alice和Bob玩一个游戏,喷漆!现在有一棵树上边的节点最开始都没有被染色.游戏规则是: ...

  4. Linux系统编程——进程间通信(一)

    基本操作命令: ps -ajx/-aux/-ef 查看进程间状态/的相互关系 top 动态显示系统中的进程 nice 按照指定的优先级运行 /renice 改变正在运行的进程的优先级 kill -9杀 ...

  5. JVM内存分配与回收

    1.内存分配与回收策略 内存自动管理:自动化的解决了对象内存分配和回收对象内存的问题. 一般在堆上分配对象,也可能经过JTI编译后间接在栈上分配. 主要分配在新生代的Eden区,如果启动了本地线程分配 ...

  6. 【转载】 ftp 命令行

    原文在这里. 本文中,介绍在 Linux shell 中如何使用 ftp 命令.包括如何连接 FTP 服务器,上传或下载文件以及创建文件夹.尽管现在有许多不错的 FTP 桌面应用,但是在服务器.SSH ...

  7. h5游戏制作

    前言: 好久没更新博客了,以前很多都不会,所以常常写博客总结,倒是现在有点点经验了就懒了.在过去的几个月里,在canvas游戏框架方面,撸过了CreateJS,玩得了Egret,又学过PIXI.js. ...

  8. PHP7.3发布啦

    作为PHP5的最后一个版本,也是目前使用最广泛的PHP版本,PHP 5.6始于公元2014年(不是1804年,嘿嘿),其第一个测试版PHP 5.6 alpha 1版于2014年1月发布.随机产生了第一 ...

  9. LoadRunner中的C Vuser函数

    LoadRunner中的C Vuser函数     事务函数: lr_end_sub_transaction 标记子事务的结束以便进行性能分析. lr_end_transaction 标记事务的结束. ...

  10. 微软企业库5.0 学习之路——第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—下篇

    在上一篇文章中, 我介绍了企业库Cryptographer模块的一些重要类,同时介绍了企业库Cryptographer模块为我们提供的扩展接口,今天我就要根据这些 接口来进行扩展开发,实现2个加密解密 ...