Dijkstra模板
struct edge
{
int to,cost;
};
vector<edge>v[1010];
typedef pair<int,int>p;
int dis[1010];
int n;
void dijkstra()
{
fill(dis+1,dis+n+1,INF);
dis[1]=0;
priority_queue<p,vector<p>,greater<p> >q;
q.push(p(0,1));
while(!q.empty())
{
p temp=q.top();
q.pop();
int w=temp.first;int id=temp.second;
if(w>dis[id])continue;
for(int i=0;i<v[id].size();i++)
{
edge &e=v[id][i];
if(w+e.cost<dis[e.to])
{
dis[e.to]=w+e.cost;
q.push(p(dis[e.to],e.to));
}
}
}
}
floyd模板
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
dis[i][j]=dis[i][j]||(dis[i][k]&&dis[k][j]);
spfa模板
struct edge
{
int to;
int cost;
};
vector<edge>v[2510];
double dis[2510];
bool vis[2510];
int cnt[2510];
int n,tp;
double w;
bool spfa()
{
fill(dis+1,dis+1+n,INF);
fill(vis+1,vis+1+n,false);
fill(cnt+1,cnt+1+n,0);
queue<int>q;q.push(1);
vis[1]=true;dis[1]=0;cnt[1]++;
while(!q.empty())
{
tp=q.front();vis[tp]=false;
q.pop();
for(int i=0;i<v[tp].size();i++)
{
edge &e=v[tp][i];
if(dis[tp]+e.cost<dis[e.to])
{
dis[e.to]=dis[tp]+e.cost;
if(!vis[e.to])
{
q.push(e.to);
vis[e.to]=true;
cnt[e.to]++;
if(cnt[e.to]>n)return true; //判断负环
}
}
}
}
return false;
}
POJ 2253
题意:
有两只青蛙和若干块石头,现在已知这些东西的坐标,两只青蛙A坐标和青蛙B坐标是第一个和第二个坐标,现在A青蛙想要到B青蛙那里去,并且A青蛙可以借助任意石头的跳跃,而从A到B有若干通路,问从A到B的所有通路上的最大边。
解题思路:
求所有通路中间最长的一段路的最小值,让dis[i]存从1到i的最长的一段路,然后max(dis[id],e.cost)<dis[e.to]更新即可。
POJ 1797
题意:
找一条从 1 到 n 的道路,使得这条道路的每段距离中的最小值最大。
解题思路:
求所有通路中间最短的一段路的最大值,让dis[i]存从1到i的最短的一段路,然后min(dis[id],e.cost)>dis[e.to]更新即可。
POJ 3268
题意:
有编号为1-N的牛,它们之间存在一些单向的路径。给定一头牛的编号,其他牛要去拜访它并且拜访完之后要返回自己原来的位置,求这些牛中所花的最长的来回时间是多少。
解题思路:
返回的最短路直接把原来的出边变成入边再dijkstra一次即可。
POJ 3660
题意:
有n头牛比赛,m种比赛结果,最后问你一共有多少头牛的排名被确定了,其中如果a战胜b,b战胜c,则也可以说a战胜c,即可以传递胜负。求能确定排名的牛的数目。
解题思路:
传递闭包再根据出度+入度即可。
POJ 1860
题意:
给定N种货币,某些货币之间可以相互兑换,现在给定一些兑换规则,问能否从某一种货币开始兑换,经过一些中间货币之后,最后兑换回这种货币,并且得到的钱比之前的多。
解题思路:
判断有没有正权回路,如果有正权回路的话会一直循环下去,就相当于最短路里面判断有没有负权回路,dis[i]里面装可以换的钱,如果松弛成功(钱变多了)就更新,spfa计数判断某个点进入队列的次数超过n次就有正权回路。
POJ 3159
题意:
给n个人分糖果,m组数据a,b,c;意思是a比b少的糖果个数绝对不超过c个,也就是d(b)-d(a) < c,求1比n少的糖果数的最大值。
解题思路:
差分约束,因为要使dis[B]<dis[A]+e.cost,所以修改一下松弛条件dis[id]+e.cost<dis[e.to]即可(因为刚开始初始化的dis[e.to]是INF,所以松弛要使它变小)。
给出一些形如x-y<=b不等式的约束,问你是否满足有解的问题,这类问题可以转换成图论里的最短路径问题。
在单源最短路径的算法中有一步是“若d[v] > d[u]+cost[u][v],则d[v]= d[u] + cost[u][v],这样就满足d[v]-d[u]<=cost[u][v]”。
如此,如果要求最大值,把每个不等式变为标准x-y<=k的形式,然后建立一条从y到x的权值为k的边,求出最短路径即可;
如果要求最小值,把每个不等式变为标准x-y>=k的形式,然后建立一条从y到x的权值为k的边,求出最长路径即可;
注意:x-y<k,x-y<=k-1,大于同理;一般题目中除了明面上的约束,还会有一些隐藏的约束;由于差分约束系统常出现负权,故一般用SPFA;如果存在负环,则此约束系统不存在。
这里直接spfa会超时…说是要手写stack…用dijkstra+priority_queue也可,不过要用链式向前星来存储边。
链式向前星:http://blog.csdn.net/acdreamers/article/details/16902023
结构体:
struct edge
{
int to;
int cost;
int next;
}eg[150010];
head[]数组一般初始化为-1,对于加边的add函数是这样的:
void add(int a,int b,int c)
{
eg[top].cost=c;
eg[top].to=b;
eg[top].next=head[a];
head[a]=top++;
}
遍历时:
for(int i=head[id];i!=-1;i=eg[i].next)
POJ 1062
题意:
有N个物品,每个物品都有自己的价格,但同时某些物品也可以由其他的(可能不止一个)替代品,这些替代品的价格比较“优惠”,问怎么样选取可以让你的花费最少来购买到物品1。
解题思路:
建图只要设立一个原点即可,这里要注意题目条件是连间接接触都不行的,所以要枚举范围,而不是直接判断相邻的。
LightOJ 1074
题意:
给定每条街的拥挤度p(x),街a到街b的时间就是(p(b)-p(a))*3,求第一个点到第k个点的最短路,若无法到达或结果小于3,输出’?’。
解题思路:
这里可能会出现负环的情况…这样的话while(!q.empty())会停不下来,判断个负环,然后dfs标记所有负环上的点,注意while(!q.empty())里面不要忘了if(cir[i])continue;
void dfs(int x) //dfs标记环上的点
{
cir[x]=true;
for(int i=0;i<v[x].size();i++)
if(!cir[v[x][i].to])
dfs(v[x][i].to);
}
HDU 4725
题意:
每个点放在一层,然后给了n个点,相邻的两层距离是固定的t,有额外m条边,然后求1到n的最短路径,如果没有则输出-1。
解题思路:
难点在于建图。要将层抽象出来成为n个点(对应编号依次为n+1~n+n),然后层与层建边,点与点建边,层与在该层上的点建边(边长为0)(这时只要考虑该层进入这个点),点与相邻层建边(边长为c)(这时只要考虑从点出去),spfa+vector会TLE,用dijkstra+vector,或者spfa+链式前向星。
POJ 3169
题意:
一些母牛按序号排成一条直线。有两种要求,A和B距离不得超过X,还有一种是C和D距离不得少于Y,问可能的最大距离。如果没有输出-1,如果可以随便排输出-2,否则输出最大的距离。
解题思路:
差分约束。根据题目可得三个要求:s[i+1]-s[i]>=0;s[B]-s[A]<=D(ML);s[B]-s[A]>=D(MD)。看s[B]-s[A]<=D这个条件,因为最开始dis[i]初始化为INF,所以if(s[A]+D<s[B])s[B]=s[A]+D,是不是觉得这个条件很眼熟?就是最短路松弛的条件呀…所以就是最短路啦…也就是题目要求的最长…建边即可(A,B,D),这样子一来,也可以把其他条件变一变,也可以变成这个样子来建边,s[A]-s[B]<=-D,建边(B,A,-D),s[i]-s[i+1]<=0,建边(i+1,i,0),建好图就跑一下spfa。如果出现负环,则说明无解,因为可以一直松弛下去,如果dis[i]==INF,就相当于1到i不连通,没有约束,则说明可以是任意解。
POJ 4370
题意:
一个n*n的01矩阵,满足以下条件
X12+X13+…X1n=1
X1n+X2n+…Xn-1n=1
for each i (1<i<n), satisfies ∑Xki (1<=k<=n)=∑Xij (1<=j<=n).
另给出一个矩阵C,求∑Cij*Xij(1<=i,j<=n)的最小值。
解题思路:
每个Xij都可以看做是一条路,X12+X13+……+X1n=1说明1的出度是1,X1n+X2n+……+Xn-1n=1说明n的入度是1,Xki(1<=k<=n) = Xij(1<=j<=n)说明其他点的入度等于出度,定一个超级原点和一个超级汇点,Xij=1的就是要选的那条路,这里跑一下1~n的最短路即可,但是,还要考虑一种情况,题没有说1的入度和n的出度情况,所以,可能存在1号点经过其它点成环,n号点经过其它点成环,这两个环的花费之和的情况,那么怎么求1或者n的最小花费环呢?可以直接搜索,也可以在跑最短路的时候先别把起始点入队,把起始点连接的所有点入队,这样跑完之后,到起始点的最短距离就是最小环了。
最短路中dijkstra最终所有最短路走的边,可以根据每次标记d[i]:这个点紧连的那条边的编号来得到。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!