这是集训队之前的题目,翻出来重新做。在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;
}
对了,想起了参考别人代码时候自己懂了还是不会写,是因为不懂得怎么样去保存原来的数据。
后来再看到百度上用结构体来复制整个数组的方法就有大概的印象。
改代码是时候就直接用函数隐式复制数据,以留着继续计算。看上去做得还不错~