洛谷 P1938 【[USACO09NOV]找工就业Job Hunt】题解

  • 因为有边权,还是求最值,想到最 长路,可是点权不好处理到最长路算法中。所以,想到把点权放到边权中,即 G i . w = D − T i G_{i}.w = D - T_{i} Gi.w=DTi,这样就可以直接跑最长路了
  • 至于如何计算最长路,主要有两种方法。法一,是将最长路转化为最短路,所以插入边权时,直接取反即可;法二,是直接改spfa中判断的部分(可以参考代码SPFA里的判断)
  • 输出 − 1 -1 1的情况就是当有正环。肯定使用SPFA,记录一个cnt数组保存每个节点入队次数,若 c n t i > n cnt_{i} > n cnti>n,说明有正环
  • 代码:(SPFA版)
# include <iostream>
# include <cstdio>
# include <queue>

using namespace std ;

struct Edge{	
	int to , next , w ;
} g[1005] ;

int d , p , c , f , s ;

int fte[225] , gsz , cnt[225] ;

void addedge( int x , int y , int z )
{
	g[++ gsz] = ( Edge ) { y , fte[x] , z } ;
	fte[x] = gsz ;
}
int dis[225] ;
bool already[225] ;
queue < int > q ;

bool spfa( int s )
{
	for ( int i = 1 ; i <= c ; i++ )
		dis[c] = -1e9 , already[i] = false ;
	dis[s] = d ;
	already[s] = 1 ;
	q.push( s ) ;
	while ( ! q.empty() )
	{
		int x = q.front() ;
		cnt[x] ++ ;
		if ( cnt[x] > c )
			return false ;
		already[x] = 0 ;
		q.pop() ;
		for ( int i = fte[x] ; i ; i = g[i].next )
		{
			int y = g[i].to ;
			if ( dis[x] + g[i].w <= dis[y] ) //注意,这里要改成大于才改,小于等于不改
				continue ;
			dis[y] = dis[x] + g[i].w ;
			if ( already[y] )
				continue ;
			already[y] = 1 ;
			q.push( y ) ;
		}
	}
	return true ;
}

int main()
{
	scanf("%d%d%d%d%d" , &d , &p , &c , &f , &s) ;
	for ( int i = 1 ; i <= p ; i++ )
	{
		int x , y ;
		scanf("%d%d" , &x , &y) ;
		addedge( x , y , d ) ;
	}
	for ( int i = 1 ; i <= f ; i++ )
	{
		int x , y , w ;
		scanf("%d%d%d" , &x , &y , &w) ;
		addedge( x , y , d - w ) ;
	}
	if ( ! spfa( s ) )
	{
		puts("-1") ;
		return 0 ;
	}
	int ans = -1e9 ;
	for ( int i = 1 ; i <= c ; i++ )
		ans = max( ans , dis[i] ) ;
	printf("%d\n" , ans) ;
	return 0 ;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值