题目链接,可TP
------------------------------------------------------------------------------------------------------
先介绍一下 SPFA:
SPFA算法是1994年西安交通大学 段凡丁 提出的。一种求单元最短路的算法。
算法中需要用到的主要变量
int n;//表示n个点,从1到n标号
int s,t;//s为起点,t为终点
int d[N]; //d[i]表示起点s到点i的最短路
int p[N]; //记录路径(或者说记录前驱)
queue
int vis[N]; // vis[i] = 1表示点i在队列中,vis[i]= 0 表示 不在队列中
------------------------------------------------------------------------------------------------------
几乎所有的最短路算法其步骤都可以分为两步:
1.初始化
d数组全部复制为MAX (无穷大),p数组全部为s (即起点),或者赋值为-1,表示还没有知道前驱,然后d[s] = 0;表示起点不用求最短路径,或者说最短路 就是0,将起点入队;
2.松弛操作
读取队头顶点u,并将队头顶点u出队(消除标记);将与点u相连的虽有点v进行松弛操作,如果更新估计值(即令d[v]变小),那么就更新,另外,如果点v没有在队列中,那么要将点v入队(标记),如果已经在队列中,不用入队。
以此循环,知道队列为空时,完成了单源最短路的求解。
------------------------------------------------------------------------------------------------------
SPFA可以处理负权边
定理:只要最短路径存在,上述SPFA算法必定能求出最小值。
证明:每次将点放入队尾,都是经过松弛操作达到的。换言之,每次的优化将会有某个点V的最短路径估计值d[V]变小。所以算法的执行会使d越来越小。由于我们假定图中不存在负权回路,所以每个结点都有最短路径值。因此,算法不会无限执行下去,随着d值的变小,直到到达最短路径值时,算法结束,这时的最短路径估计值就是对应结点的最短路径值。(证明完毕)
期望的时间复杂度O(ke),其中k味儿所有顶点进队的平均次数。可以证明k一般小于等于2.
判断有无负环:
如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)
SPFA的两种写法,bfs 和 dfs ,bfs判别负环不稳定,相当于限深度搜索,但是设置得好的的话还是没没问题的,dfs的话判断负环还是很快的
------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX 99999999
using namespace std;
int mp[205][205];
int dis[205];
int vis[205];
int n,m;
int st,en;
void SPFA()
{
int i;
//初始化路线总和 && 初始化标记
for(i=0;i q;
while(!q.empty())
q.pop();
//起始点标记
dis[st]=0;
vis[st]=1;
q.push(st);
while(!q.empty())
{
int t;
t=q.front();
q.pop();
vis[t]=0;
for(i=0;idis[t]+mp[t][i])
{
dis[i] = dis[t] + mp[t][i];
//若没有走过,标记已经走过,并放入队列
if( !vis[i])
{
vis[i]=1;
q.push(i);
}
}
}
}
int main()
{
int u,v,cost;
int i,j;
while(cin>>n>>m)//n为点,m为边
{
//初始化邻接矩阵
for(i=0;i>u>>v>>cost;
if(cost>st>>en;
//SPFA
SPFA();
//输出结果
if(dis[en] < MAX)
cout<
题目大意:
输入一个整数n,(1<=n<=50.000)n表示有n个区间,接下来n行,每行3个数ai,bi,ci(0<=ai<=bi<=50.000 and 1<= ci<= bi-ai+1)在ai到bi中间 有ci个数要取出,求总共要去除多少数
思路:
百度了一下。此题需用:差分约束+spfa,思路看---->链接
百度大法好呀,百度大法好!
#include
#include
#include
#include
#include
using namespace std;
const int M = 151010;
const int INF = -9999999;
struct Edge //邻接表
{
int v;
int w;
int next; //
} edge[M];
int dis[M];
int head[M]; //保存边的头结点编号
bool visit[M];
int num,n,maxx,minn;
int number ;
queue p;
int SPFA()
{
int e;
for(int i = minn; i <= maxx; i++)
dis[i] = INF;
dis[minn] = 0;
p.push(minn);//源点入队
visit[minn] = true; //标记在队中
while( !p.empty() )
{
e = p.front();
p.pop();
visit[e] = false; //标记不在队中
for(int i = head[e]; i != -1; i = edge[i].next)
{
if (dis[edge[i].v] < dis[e] + edge[i].w) //找最长路,三角不等式
{
dis[edge[i].v] = dis[e] + edge[i].w;
if( !visit[edge[i].v] )
{
visit[edge[i].v] = true;
p.push(edge[i].v);
}
}
}
}
return dis[maxx];
}
int main()
{
int a,b,c;
num = 0;
number = 1;
maxx = -9999;
minn = 9999;
memset(dis,0,sizeof(dis));
memset(head,-1,sizeof(head)); //不要写0啊啊啊啊
memset(visit,false,sizeof(visit));
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a >> b >> c;
edge[num].next = head[a];
edge[num].v = b + 1;
edge[num].w = c;
head[a] = num;
num ++;
if(maxx < b+1)
maxx = b+1;
if(minn > a)
minn = a;
}
for(int i = minn; i < maxx; i++)
{
edge[num].next = head[i];
edge[num].v = i+1;
edge[num].w = 0;
head[i] = num;
num++;
edge[num].next = head[i+1];
edge[num].v = i;
edge[num].w = -1;
head[i+1] = num;
num++;
}
int ans = SPFA();
cout << ans <
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define maxn 1100
using namespace std;
struct node {
int u, v, w, next;
};
node edge[1100000];
int dist[maxn], head[maxn], cnt;
int used[maxn], n, ML, MD;
bool vis[maxn];
//初始化
void init()
{
cnt = 0;
memset(head, -1, sizeof(head));
memset(used, 0, sizeof(used));
memset(vis, 0 ,sizeof(vis));
}
void add(int u, int v, int w)
{
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u] = cnt++;
}
//输入ML和MD的两种情况
void getmap()
{
int a, b, d;
for(int i = 1; i <= n; ++i)
add(i + 1, i, 0);
//增加最大距离
while(ML--)
{
cin>>a>>b>>d;
add(a, b, d);
}
//减掉最短距离
while(MD--)
{
cin>>a>>b>>d;
add(b, a, -d);
}
}
void SPFA(){
for(int i = 1; i <= n; ++i)
dist[i] = INF;
dist[1] = 0;
queueq;
vis[1] = 1;
used[1] = 1;
q.push(1);
while(!q.empty())
{
int u = q.front();
q.pop();
if(used[u] > n)
{
printf("-1\n");
return ;
}
vis[u] = 0;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
int w = edge[i].w;
if(dist[v] > dist[u] + w)
{
dist[v] = dist[u] + w;
if(!vis[v])
{
vis[v] = 1;
used[v]++;
q.push(v);
}
}
}
}
if(dist[n] == INF)
cout<<"-2"<>n>>ML>>MD)
{
init();
getmap();
SPFA();
}
return 0;
}
输入N,N组测试,每一组测试输入P,Q两个数,(1<=P,Q<=1,000,000),最大数字为P,接下来有Q行,每一行a,b,w,在a,b之间的路线权为w,这是个有向图。
思路:
按照上面几道题的思路
百度大法好呀,百度大法好
#include
#include
#include
#define nMax 1000010
#define eMax 10000010
#define inf 1000000010
struct EDGE
{
int v,w,next;
}edge[nMax], reEdge[nMax];
int nEdge[nMax], nReEdge[nMax];
int n, m, queue[eMax];
__int64 dis[nMax], sum;
bool vis[nMax];
void edgeInit()
{
for (int i = 1; i <= n; ++ i)
{
nEdge[i] = 0;
nReEdge[i] = 0;
}
}
void spfaInit()
{
for (int i = 1; i <= n; ++ i)
{
dis[i] = inf;
vis[i] = false;
}
}
void spfa(int * nEdge, EDGE * edge)
{
spfaInit();
int head = 0, tail = 1;
dis[1] = 0;
queue[0] = 1;
while (head < tail)
{
int u = queue[head];
vis[u] = true;
int p = nEdge[u];
while (p != 0)
{
int v = edge[p].v, w = edge[p].w;
if (dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if (!vis[v])
{
vis[v] = true;
queue[tail] = v;
tail ++;
}
}
p = edge[p].next;
}
vis[u] = false;
head ++;
}
for (int i = 1; i <= n; ++ i)
{
sum += dis[i];
}
}
int main()
{
int t;
scanf("%d", &t);
while (t --)
{
scanf("%d%d", &n, &m);
edgeInit();
for (int i = 1; i <= m; ++ i)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edge[i].v = v;
edge[i].w = w;
edge[i].next = nEdge[u];
nEdge[u] = i;
reEdge[i].v = u;
reEdge[i].w = w;
reEdge[i].next = nReEdge[v];
nReEdge[v] = i;
}
sum = 0;
spfa(nEdge, edge);
spfa(nReEdge, reEdge);
printf("%I64d\n", sum);
}
return 0;
}
题目大意:
输入两个整数n,m(1
思路:
总的思路差不多。然后主要是再多一个花费。
这题不百度不行啊!............
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAX = 1100;
const int INF = 0x3fffffff;
struct Node
{
int len;
int money;
};
Node map[MAX][MAX];
Node dis[MAX];
bool used[MAX];
Node SPFA(int start,int end,int n)
{
int i;
//初始化
for(i=1;i<=n;i++)
{
dis[i].len = INF;
dis[i].money = INF;
}
//起始位置
dis[start].len = 0;
dis[start].money = 0;
//建立队列
queue q;
q.push(start);
used[start] = 1;
while(!q.empty())
{
int mid;
mid = q.front();
q.pop();
used[mid] = 0;
for(i=1;i<=n;i++)
{
//松弛操作
if(map[mid][i].len + dis[mid].len < dis[i].len)
{
dis[i].len = map[mid][i].len + dis[mid].len;
dis[i].money = map[mid][i].money + dis[mid].money;
if(!used[i])
{
q.push(i);
used[i] = 1;
}
}
//当最短距离有多条的时候,输出花费最少的
if(map[mid][i].len + dis[mid].len == dis[i].len && dis[i].money > map[mid][i].money + dis[mid].money)
{
dis[i].money = map[mid][i].money + dis[mid].money;
}
}
}
return dis[end];
}
int main()
{
int n,m;
while(cin>>n>>m,n+m)
{
int i,j;
//初始化邻接矩阵
for(i=1;i>a>>b>>c>>d;
if(c < map[a][b].len)
{
map[a][b].len = c;
map[b][a].len = c;
map[a][b].money = d;
map[b][a].money = d;
}
}
//输入起始点,和结束点
int s,e;
cin>>s>>e;
//SPFA
Node x = SPFA(s,e,n);
//输出结果
cout<