POJ1716—差分约束系统+Bellman-Ford算法 || SPFA算法的实现

来源:互联网 发布:页面刷新js 编辑:程序博客网 时间:2024/05/16 09:02

题目看去有点难下手,如果学习了差分约束系统或是贪心算法会觉得很简单。

刚开始时用Bellman-Ford算法解,采用的是求最短路径,由于Bellman-Ford算法复杂度本身就高,再加上增设了m+1条边,时间复杂度就更高了,所依超时了,后来改用求最大路径,不用增设源节点,这样就省时多了。提交后用时两百多毫秒,还算快。然后用SPFA算法再写了一遍,算是开拓思路,温习算法吧,用时32ms。

#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int maxn=10002;int m,num,dist[maxn];struct Edge{    int s;    int t;    int w;}edge[5*maxn];void Bellman_Ford(){    int i;    bool flag=true;    while(flag)    {        flag=false;        for(i=0;i<num;i++)        if(dist[edge[i].t]<dist[edge[i].s]+edge[i].w)        {            dist[edge[i].t]=dist[edge[i].s]+edge[i].w;            flag=true;        }    }}int main(){    int i,n,a,b;    while(scanf("%d",&n)!=EOF)    {        num=0;        scanf("%d%d",&a,&b);        edge[num].s=a;        edge[num].t=b+1;        edge[num++].w=2;        m=b+1;        for(i=1;i<n;i++)        {            scanf("%d%d",&a,&b);            edge[num].s=a;            edge[num].t=b+1;            edge[num++].w=2;            if(b+1>m)            m=b+1;        }        for(i=0;i<m;i++)        {            edge[num].s=i;            edge[num].t=i+1;            edge[num++].w=0;            edge[num].s=i+1;            edge[num].t=i;            edge[num++].w=-1;        }        memset(dist,0,sizeof(dist));        Bellman_Ford();        printf("%d\n",dist[m]-dist[0]);    }    return 0;}


 

#include <iostream>#include <cstdio>#include <cstring>#define inf 10000000using namespace std;const int maxn=10006;int m,num,dist[maxn],visit[maxn],head[maxn],queue[50*maxn]; //visit数组标志该结点是在队列外还是队列内struct Edge{    int t;    //终点    int w;    int next; //下一条边的标号}edge[8*maxn];void addEdge(int s,int t,int w){    edge[num].t=t;    edge[num].w=w;    edge[num].next=head[s];    //头插法插入,构建邻接表    head[s]=num++;}void SPFA(){    int i,j,u,v,id,first,last;    first=0;    last=0;    visit[m+1]=true;    dist[m+1]=0;    queue[last++]=m+1;      //将源结点压入队列中    while(first!=last)    {        u=queue[first++];        visit[u]=false;     //结点出队,所以要置为false        id=head[u];         //取出以结点u为起点的邻接表的表头,即第一条边的标号        while(id!=-1)        {            v=edge[id].t;            if(dist[u]+edge[id].w<dist[v] || dist[v]==inf)            {                dist[v]=dist[u]+edge[id].w;                if(!visit[v])                {                    visit[v]=true;   //值为false的结点没有入队,值为true的入队了                    queue[last++]=v;                }            }            id=edge[id].next;     //取邻接表的下一条边        }    }}int main(){    int i,j,n,a,b;    while(scanf("%d",&n)!=EOF)    {        memset(head,-1,sizeof(head));     //开始时所有头结点都指向表尾        num=0;        m=-1;        for(i=0;i<n;i++)        {            scanf("%d%d",&a,&b);            if(b+1>m)            m=b+1;            addEdge(b+1,a,-2);        }        for(i=0;i<=m;i++)        addEdge(m+1,i,0);        //增加源节点m+1        for(i=0;i<m;i++)        {            addEdge(i,i+1,1);            addEdge(i+1,i,0);        }        memset(visit,0,sizeof(visit));        for(i=0;i<=m+1;i++)        dist[i]=inf;        SPFA();        printf("%d\n",dist[m]-dist[0]);    }    return 0;}