dijikstra不能求最长路
spfa求最短路可以判断负环,求最长路可以判断正环
差分约束系统详解(解释为什么要设置超级源点,判断连通性
差分约束介绍
POJ 1364 King(非连通图的差分约束,经典好题)
再卖菜csdn
参考链接(夜深人静写算法)
//SPFA求最短路+记录路径+判断负圈
struct edge{
int from,to,cost;
};
vector > graph;
bool inqueue[MAX_N]; //记录该节点是否在队列中
int visitcount[MAX_N];//记录节点的入队次数,判断负权圈时要用到,若某节点的该次数>n则存在负权圈
int d[MAX_N]; //记录从源点到对应点的当前最短/最长路径
int father[MAX_N]; //father[i]表示i节点最短/最长路径上的上一个节点
void SPFA(int ss) //表示从ss节点开始求
{
for(int i=0;i> Q; //可以简化为queue Q,只将节点序号放入队列中
Q.push(make_pair(d[ss],ss));
while(!Q.empty())
{
pair tem=Q.top();
int dist=tem.first;
int node=tem.second;
Q.pop();
inqueue[node]=false;
//visitcount[]的更新在出队时进行,保证每个队列中的节点都能更新visitcount
if(visitcount[node]++>MAX_N)//有负权圈,直接退出算法
return;
for(int j=0;j
如若一个系统由n个变量和m个不等式组成,并且这m个不等式对应的系数矩阵中每一行有且仅有一个1和-1,其它的都为0,这样的系统称为**差分约束( difference constraints )**系统。之所以能用spfa处理差分约束问题,是因为能从差分约束的不等式组中建立图的模型。
**【例题】**N个人编号为1-N,并且按照编号顺序排成一条直线,任何两个人的位置不重合,然后给定一些约束条件。
X(X <= 100000)组约束Ax Bx Cx(1 <= Ax < Bx <= N),表示Ax和Bx的距离不能大于Cx。
Y(X <= 100000)组约束Ay By Cy(1 <= Ay < By <= N),表示Ay和By的距离不能小于Cy。
如果这样的排列存在,输出1-N这两个人的最长可能距离,如果不存在,输出-1,如果无限长输出-2。**
**【例题】**给定n(n <= 50000)个整点闭区间和这个区间中至少有多少整点需要被选中,每个区间的范围为[ai, bi],并且至少有ci个点需要被选中,其中0 <= ai <= bi <= 50000,问[0, 50000]至少需要有多少点被选中。
例如3 6 2 表示[3, 6]这个区间至少需要选择2个点,可以是3,4也可以是4,6(总情况有 C(4, 2)种 )。**
未知条件约束是指在不等式的右边不一定是个常数,可能是个未知数,可以通过枚举这个未知数,然后对不等式转化成差分约束进行求解。
**【例题】**在一家超市里,每个时刻都需要有营业员看管,R(i) (0 <= i < 24)表示从i时刻开始到i+1时刻结束需要的营业员的数目,现在有N(N <= 1000)个申请人申请这项工作,并且每个申请者都有一个起始工作时间 ti,如果第i个申请者被录用,那么他会连续工作8小时。
现在要求选择一些申请者进行录用,使得任何一个时刻i,营业员数目都能大于等于R(i)。
是一道隐含的差分约束题目,解释如下
设ai是第一天i商店的价格,bi为第二天i商店的价格
struct edge { int from,to,cost;}
edge es[MAX_N]; //该算法以 边集 为数据基础
int d[MAX_N]; //记录最短距离
int count[MAX_N]; //记录节点的松弛次数
int V,E; //节点数,边数
bool shortest_path(int s){
memset(count,o,sizeof(count));
for(int i=0;i=MAX_N) //N个节点,每个节点最多松弛N-1次
return false; //有负圈
}
}
if(!update) //不再更新说明已经找到所有最短路径
return true;
}
}//bellman-ford 的改进方法就是spfa
//使用矩阵dijkstra的复杂度为O(V^2),使用邻接表+优先队列复杂度为O(V*logE)
struct edge{
int from, to cost;
}
typedef pair P; //first为最短距离,second为节点编号
bool operator<(const P& p1,const P& p2)
{
return p1.first>=p2.first;
}
int V;
vector > graph(MAX_N);
int d[MAX_N];
void dijkstra(int s){
priority pq;
memset(d,127,sizeof(d)); //INF
d[s]=0;
pq.push(make_pair(0,s));
whlie(!pq.empty())
{
P tep=pq.top(); pq.pop();
int v=tep.second;
//队首元素是队列中最小的,但若不能松弛该节点,此时该队首元素没用(对于已经找到最小路径的节点,即使到它的另外一条路现在是队列中的最小值,也没用)
if(d[v]d[e.from]+e.cost)
{
d[e.to]=d[e.from]+e.cost; //d[]存的就是临时最短路径
pq.push(make_pair(d[e.to],e.to));
//放入队列中的都是由当前最短距离 增加一条边的联系得来的
}
}
}
}
dij+堆链接
priority_queue默认是最大的元素在队头(大顶堆)
自定义排序方式的重载: 链接 sort运算符重载
//类(结构体)的方式
struct cmp{
bool operator ()(const int& a,const int &b){
return a>b;
}
};
//在类中重载运算符<(不能在类外直接重载,除非加友元(比较麻烦所以不推荐)
struct Person{
int id;
bool operator <(const Person& b){
return this->b->id;
}
};
//定义函数
bool compare(const int& a,const int& b){
return a>b;
}
//或者 使用less或者greater对基本类型排序。
//对于sort推荐用函数compare方式,对于priority_queue一般用结构体方式
sort(arr,arr+n;compare);
sort(arr,arr+n,cmp()); //注意sort用结构体方式要cmp()
sort(arr,arr+n,greater<int>()); //注意要加(),是递减排序
priority_queue<int,vector<int>,cmp>; //pq用结构体方式直接cmp
priority_queue<int,vector<int>,greater<int>> //greater<>不用加(),最小堆
//可以发现相同的比较函数用于sort和pq是“相反的顺序”(递增-最大堆,递减-最小堆)
Floyd-Warshall算法的原理是动态规划
要将节点先编号1~n, D i , j , k D_{i,j,k} Di,j,k表示i->j 只经过1~k节点(中的若干任意节点)得到的最短路径值。
再分k节点是否在这条最短路上,有两种情况,根据这两种情况推出 D i , j , k − 1 D_{i,j,k-1} Di,j,k−1 的关系式,之后就可以用DP
时间复杂度为O(n3),空间复杂度为O(n2)