2017暑假集训 div1 最短路(2)

POJ 3660

题意:给出m对牛的相互关系,求有多少个牛排名是确定的。

做法:用floyd求传递闭包。如果 A>B, B>C 那么一定有 A>C  与Floyd 的 枚举三个点一模一样!!!


核心代码:

void floyd()
{
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=n;++j)
        {
            for(int k=1;k<=n;++k)
            {
                if(map[j][i]&&map[i][k]) map[j][k]=1;
            }
        }
    }

}


HDU 1217&&POJ2240
题意:给出一些货币和货币之间的兑换比率,问是否可以使某种货币经过一些列兑换之后,货币值增加。举例说就是1美元经过一些兑换之后,超过1美元。可以输出Yes,否则输出No。

做法:由于给出的是货币名称,所以首先我们要把货币之间的关系转化成一张图。转化时,直接用map标记号,然后就spfa 求负环问题了


POJ 1511

题意:给定节点数n,和边数m,边是单向边.问从1节点出发到2,3,...n 这些节点路程和从从这些节点回来到节点1的路程和最小值。

做法:直接正反两边spfa 扫一遍求和即可(存邻接表的同时,把反向邻接表也存上)


POJ 3159
题意:n表示有n个同学,m表示m组数据u,v,w,表示同学u要求同学v的糖果数不能多于他超过w个,问同学n和同学1的他糖果数最多相差几个??

做法:差分约束,条件很明显,运用类似最短路分析d[v] - d[u] <= w(u, v) ,也就是 d[v] <= w(u,v) + d[u];每个约束B-A<=c 就是B<=A+c  加边A->B  为c的边。用优先队列优化的dij ,求最短路

代码:


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=30010;
struct node
{
    int next,to;
    int  w;
}edge[200000];
int head[maxn],cnt=0;
void add(int u,int v,int w)
{
    edge[cnt].to=v; edge[cnt].w= w;
    edge[cnt].next= head[u] ; head[u]=cnt++;
}
int n,m;
bool vis[maxn];
int dis[maxn];
struct enode
{
    int pos,val;
    bool friend operator < (const enode a,const enode b)
    {
        return a.val>b.val;
    }
};
void dij()
{
    for(int i=1;i<=n;++i)
    {
        vis[i]=0; dis[i]=inf;
    }
    dis[1]=0;
    struct enode u,v;
    priority_queue<enode>  que;
    while(!que.empty()) que.pop();
    u.pos=1; u.val=0;
    que.push(u);
    while(!que.empty())
    {
        u=que.top() ; que.pop();
        if(vis[u.pos]) continue;
        vis[u.pos]=1;
        for(int i=head[u.pos];i!=-1;i=edge[i].next)
        {
            int to=edge[i].to;
            int w=edge[i].w;
            if(!vis[to]&&dis[u.pos]+w<dis[to])
            {
                dis[to]=dis[u.pos]+w;
                v.pos= to; v.val=dis[to];
                que.push(v);
            }

        }

    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(head,-1,sizeof(head)); cnt=0;
        for(int i=1;i<=m;++i)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
        }
        dij();
        printf("%d\n",dis[n]);
    }
    return 0;
}










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值