P1938 [USACO09NOV]找工就业Job Hunt
双倍经验,双倍工业产值
又是类似的题呢.
题中有两种边,一种是边权为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;
}
}
}
}
}