POJ3159---Candies(最短路:spfa+栈or队列)(邻接表)

【题意来源】http://poj.org/problem?id=3159
【题意】
班长分糖,规定是,B童鞋分的糖不能超过A童鞋C个(输入数据:A B C),那么,假设共有n个同学,编号1~n,那么n好同学最多比1号同学多多少个?
【思路】
不等式问题,可由差分约束系统转变为最短路问题。(差分约束现在还不大懂。。)
大致说一下我的思考过程:
假设S数组代表最优情况下每个人得到的糖的数量,那么由题意可得:
S(B)-S(A)<=C,转化为:S(B)<=S(A)+C。
那么,就可以转变为最短路问题,也即是:
if(S(B)>S(A)+C) S(B)=S(A)+C。求出最短路。
但是有的人会疑问:不是让求max(S(n)-S(1)),这样下去只会得到min(S(n)-S(1))。这个问题我也不大懂。先给出链接:浅析差分约束系统,但是按照我上面推导是大于还是小于是没有错的。。。
还有一点要说明:这道题非常卡数据、卡时间。
数据问题呢,我用双向队列试了出来,最短路的spfa算法呢,每从队列里拿出一个点(被更新过的,要么就是起点),用于更新其他点,那么假设当前取出一个点去更新完一个点后,被更新的点将何去何从?
分析:
优先队列:会被丢进队列,然后自动排序,队首依旧是最小的那个。
普通队列:会被丢进队尾,需要前面的被取出完才能被取出。
栈:会被丢进队首,当前点更新所有点之后,会被取出。
这道题,绝大部分用栈(又名堆栈)过的这道题,那么栈和队列有什么区别呢?
相同的时间复杂度下,队列是队尾进,队首出,而栈是队首进,队首出。
而优先队列就是优化了一部分多余的查找过程,队首就直接是最小的(但是可能由于卡时间,所以普通的优先队列过不了),那么,为什么队列会TLE,而栈没有呢。。。我想到的唯一原因是。。数据问题,更新的点刚好是最小的点,然后放在队首。。。
【代码1】
516ms

#include<cmath>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int n,m,tot;
struct pp
{
    int v,w;
    int nexx;
}edge[150000+10];
int vis[30000+10],d[30000+10],first[30000+10];
int spot[30000+10];
void spfa()
{
    memset(vis,0,sizeof(vis));
    for(int i=2;i<=n;i++)
        d[i]=INF;
    d[1]=0;
    int top=1;
    spot[1]=1;
    vis[1]=1;
    while(top!=0)
    {
        int res=spot[top--];
        vis[res]=0;
        for(int i=first[res];i!=-1;i=edge[i].nexx)
        {
            if(d[edge[i].v]>d[res]+edge[i].w)
            {
                d[edge[i].v]=d[res]+edge[i].w;
                if(!vis[edge[i].v])
                {
                    spot[++top]=edge[i].v;
                    vis[edge[i].v]=1;
                }
            }
        }
    }
    printf("%d\n",d[n]);
}
int main()
{
    scanf("%d%d",&n,&m);
    tot=0;
    for(int i=1;i<=n;i++)
        first[i]=-1;
    while(m--)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        edge[tot].nexx=first[u];
        edge[tot].v=v;
        edge[tot].w=w;
        first[u]=tot++;
    }
    spfa();
}

【代码2】
deque(双向队列)实现的栈的功能(实现的队列依旧会TLE)657ms

#include<cmath>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int n,m,tot;
struct pp
{
    int v,w;
    int nexx;
}edge[150000+10];
int vis[30000+10],d[30000+10],first[30000+10];
int spot[30000+10];
void spfa()
{
    memset(vis,0,sizeof(vis));
    for(int i=2;i<=n;i++)
        d[i]=INF;
    d[1]=0;
    deque<int> q;
    vis[1]=1;
    q.push_back(1);
    while(!q.empty())
    {
        int res=q.front();
        q.pop_front();
        vis[res]=0;
        for(int i=first[res];i!=-1;i=edge[i].nexx)
        {
            if(d[edge[i].v]>d[res]+edge[i].w)
            {
                d[edge[i].v]=d[res]+edge[i].w;
                if(!vis[edge[i].v])
                {
//                    if(!q.empty()&&d[edge[i].v]<d[q.front()])
                    q.push_front(edge[i].v);
//                        else
//                    q.push_back(edge[i].v);
                    vis[edge[i].v]=1;
                }
            }
        }
    }
    printf("%d\n",d[n]);
}
int main()
{
    scanf("%d%d",&n,&m);
    tot=0;
    for(int i=1;i<=n;i++)
        first[i]=-1;
    while(m--)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        edge[tot].nexx=first[u];
        edge[tot].v=v;
        edge[tot].w=w;
        first[u]=tot++;
    }
    spfa();
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值