昂贵的聘礼,很昂贵

这是集训队之前的题目,翻出来重新做。在wa了好几次参考了别人代码之后再改,过了。


是什么:探险家每交换一个物品就有可能省下一部分钱,找出能省出最多多少钱。可以化成最长路问题(类似于最短路问题),用dijkstra算法做。

为什么:把“优惠”的数值记下了,代表边权。这样就可以化成最长路问题做了。

怎么样:遍历连接点(起初的物品)的边集,更新边的另一个结点的(物品)的最大省下的钱的。再遍历所有的点,找出最大的的点就是答案了。



以下是代码:

ps:自己很不喜欢用数组把有关联的数据分开,于是就用结构体代替了。

代码中  nda 是 nodedata 

              eda 是 edgedata

看上去很乱,但是自己写出了会觉得很清晰~见仁见智吧。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
struct node{
	int lev,start,cost,totsave;
	node(int a=0,int b=0){
		lev=b;
		cost=a;
		totsave=0;
		start=-1;
	}
};
struct edge{
	int sta,end,cost,save,next;
	edge(int a,int b,int c){
		sta=a;
		end=b;
		cost=c;
		save=0;
	}
	edge(){}
};
int abs(int a){
	if(a<0) return -a;
	return a;
}
int spfa(node nda[],edge eda[],int sleve,int m,int n){
	queue<int> que;
	nda[0].totsave=0;
	while(!que.empty()) que.pop();
	que.push(1);
	while(!que.empty()){
		int cur=que.front();
		que.pop();
		for(int x=nda[cur].start;x!=-1;x=eda[x].next){
			if(nda[eda[x].end].totsave<nda[eda[x].sta].totsave+eda[x].save&&nda[eda[x].end].lev>=sleve&&nda[eda[x].end].lev<=sleve+m){
				nda[eda[x].end].totsave=nda[eda[x].sta].totsave+eda[x].save;
				que.push(eda[x].end);
			}
		}
	}
	int maxx=0;
	for(int i=1;i<=n;++i)
		maxx=max(maxx,nda[i].totsave);
	return nda[1].cost-maxx;
}
int main(){
	int m,n;
	while(scanf("%d%d",&m,&n)!=EOF){
		node nda[130];
		edge eda[12000];
		int ta,tb,tc,td,te,k=0;
		int want;
		for(int i=1;i<=n;++i){
			scanf("%d%d%d",&ta,&tb,&tc);
			if(i==1) want=tb;
			node tmp(ta,tb);
			nda[i]=tmp;
			
			for(int j=0;j<tc;++j){
				scanf("%d%d",&td,&te);
				eda[k].sta=i;
				eda[k].end=td;
				eda[k].cost=te;
				eda[k].save=ta-te;
				eda[k].next=nda[i].start;
				nda[i].start=k;
				++k;
			}
		}
		for(int i=0;i<k;++i){
			eda[i].save-=nda[eda[i].end].cost;
		}
		
		int ans=nda[1].cost;
		for(int i=want-m;i<=want;++i){
			ans=min(ans,spfa(nda,eda,i,m,n));
		}
		cout<<ans<<endl;
	}
	return 0;
}

对了,想起了参考别人代码时候自己懂了还是不会写,是因为不懂得怎么样去保存原来的数据。

后来再看到百度上用结构体来复制整个数组的方法就有大概的印象。

改代码是时候就直接用函数隐式复制数据,以留着继续计算。看上去做得还不错~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值