P1938找工就业与P2648赚钱团结如一题(大雾)的题解

P1938 [USACO09NOV]找工就业Job Hunt

P2648 赚钱

双倍经验,双倍工业产值

又是类似的题呢.

题中有两种边,一种是边权为0的,即题中的步行通道,一种是边权为负数的,即题中的飞行航线.

然后每个点上有一个权值.

所以说大体上就是用SPFA跑一遍最长路.

但是显而易见,这道题中存在环,为了防止这个不限赚钱时间的奶牛成为资产阶级,我们要制裁它.

而且如果存在环的话就一定是正权的环.

然后推理一下就可以发现,一个有n个点的图中的任意一个点,最多被遍历n-1次(这种情况就是一个菊花图),如果遍历的次数大于n,就说明存在环了.

开一个数组记录一下每个点被遍历的次数就可以了.

之后是第二道题,可以从任意一个点开始赚钱.

我一开始想的是跑n遍SPFA,还好数据水没TLE.

后来想了一下,可以开一个虚构的点来连接所有的点,然后从这个点开始遍历.

我就没有去代码实现了.

下面是第一题的代码,第二题的稍微改一下就可以了.


#include<bits/stdc++.h>

using namespace std;

queue<int>q;

struct edge
{
    int to,next,val;
}e[510];

int d,p,c,f,s,size,ans=-2147483647,cnt=1;
int head[230],dis[230],in[230];
bool flag[230];

void edge_add(int,int,int);
void SPFA();

int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d%d%d%d",&d,&p,&c,&f,&s);
    for(int i=1;i<=p;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        edge_add(a,b,0);
    }
    for(int i=1;i<=f;i++)
    {
        int a,b,v;
        scanf("%d%d%d",&a,&b,&v);
        edge_add(a,b,-v);
    }
    SPFA();
    for(int i=1;i<=c;i++)ans=ans<dis[i]?dis[i]:ans;
    printf("%d\n",ans);
return 0;
}

void edge_add(int from,int to,int val)
{
    e[++size].to=to;
    e[size].val=val;
    e[size].next=head[from];
    head[from]=size;
}

void SPFA()
{
    memset(flag,false,sizeof(flag));
    memset(dis,-0x3f,sizeof(dis));
    dis[s]=d;
    q.push(s);
    flag[s]=true;
    while(!q.empty())
    {
        int from=q.front();
        q.pop();
        flag[from]=false;
        for(int i=head[from];i!=-1;i=e[i].next)
        {
            int to=e[i].to;
            int val=e[i].val;
            if(dis[to]<dis[from]+val+d)
            {
                in[to]++;
                if(in[to]>c)
                {
                    printf("-1\n");
                    exit(0);
                }
                dis[to]=dis[from]+val+d;
                if(flag[to]==false)
                {
                    q.push(to);
                    flag[to]=true;
                }
            }
        }
    }
}

转载于:https://www.cnblogs.com/Lemir3/p/11061539.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值