USACO Training Section 3.2 Sweet Butter

[url="http://ace.delos.com/usacoprob2?a=KxExhYBcUZv&S=butter"]英文原题[/url] [url="http://www.wzoi.org/usaco/main.asp?dir=15&wenjian=611"]中文题译[/url]

大意:农场之间有路构成稀疏无向图,若干奶牛分散在不同农场,要让奶牛到某个农场集合,如何代价最小。

稀疏图上求到所有点对的最短路径,用Bellman Ford算法的队列实现(SPFA),其思想是:开始时队列中只有源节点,不断取出队列中的首节点,并对其相邻节点检查是否可用该节点更新其距离,若可,且相邻节点不在队中,则将其入队。这和宽度优先搜索很像,所不同的是每个节点可以多次入队。

在求得最短路径之后计算集合的代价取最小值即可。


/*
ID: blackco3
TASK: butter
LANG: C++
*/
#include <iostream>
#include <memory.h>
using namespace std;
#define _max_farm_ 800
#define _max_path_ 1450
#define _max_cow_ 500

struct t_path {
int v1, v2, dis ;
} pathes[_max_path_];
struct t_adj {
int to, dis ;
t_adj( int t=0, int d=0 ) : to(t), dis(d) {} ;
} adj_buf[_max_path_<<1] ;
struct t_farm {
int n_adj ;
t_adj *adj ;
} farms[_max_farm_];
int cows[_max_cow_], n_cow, n_farm, n_path;

int sdis[_max_farm_], queue[_max_farm_], in_que[_max_farm_] ;
void Bellman_Ford_SPFA( int source ){
memset( sdis, 0x7f, sizeof(int)*n_farm );
memset( in_que, 0, sizeof(int)*n_farm ) ;
int *head=queue, *tail=queue;
sdis[source]=0 , in_que[source]=1, *(tail++)=source ;
do{
register int cfarm= *head ;
in_que[cfarm]=0, head = (head-queue)==_max_farm_-1 ? queue : head+1;
for( t_adj *p_adj=farms[cfarm].adj; p_adj!=farms[cfarm].adj+farms[cfarm].n_adj; p_adj++ ){
if( p_adj->dis + sdis[cfarm] >= sdis[p_adj->to] )
continue ;
sdis[p_adj->to] = p_adj->dis + sdis[cfarm] ;
if( !in_que[p_adj->to] ){
*tail=p_adj->to , in_que[p_adj->to]=1 ;
tail = (tail-queue)==_max_farm_-1 ? queue : tail+1;
}
}
}while( head!=tail );
}


int main() {
freopen("butter.in", "r", stdin);
freopen("butter.out", "w", stdout);
cin >> n_cow >> n_farm >> n_path ;
for( int i=0; i<n_cow; i++ )
cin >> cows[i], cows[i]-- ;
memset( farms, 0, sizeof(t_farm)*n_farm ) ;
for( t_path *pc=pathes; pc!=pathes+n_path; pc++ ){
cin >> pc->v1 >> pc->v2 >> pc->dis ;
farms[--pc->v1].n_adj++, farms[--pc->v2].n_adj++ ;
}
t_adj *p_adj=adj_buf;
for( int i=0; i<n_farm; i++ )
farms[i].adj=p_adj, p_adj+=farms[i].n_adj, farms[i].n_adj=0 ;
for( t_path *pc=pathes; pc!=pathes+n_path; pc++ ){
int v1=pc->v1, v2=pc->v2, dis=pc->dis ;
farms[v1].adj[ farms[v1].n_adj++ ]=t_adj(v2,dis);
farms[v2].adj[ farms[v2].n_adj++ ]=t_adj(v1,dis);
}
int min_total=0x7fffffff ;
for( int i=0; i<n_farm; i++ ){
Bellman_Ford_SPFA(i);
int total=0 ;
for( int j=0; j<n_cow; j++ )
total += sdis[ cows[j] ] ;
min_total = min_total>total ? total : min_total ;
}
cout << min_total << endl ;
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值