luogu3778/bzoj4898 商旅 (floyd+分数规划+spfa)
Posted ressed
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu3778/bzoj4898 商旅 (floyd+分数规划+spfa)相关的知识,希望对你有一定的参考价值。
首先floyd求出来每两点间的最短距离,然后再求出来从某点买再到某点卖的最大收益
问题就变成了找到一个和的比值最大的环
所以做分数规划,二分出来那个答案r,把边权变成w[i]-r*l[i],再做spfa判正环就行了
(本来想偷懒用floyd判正环,结果T了)
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 using namespace std; 5 typedef long long ll; 6 const int maxn=110,maxm=10010,maxk=1010; 7 const ll inf=1e15; 8 9 inline ll rd(){ 10 ll x=0;char c=getchar();int neg=1; 11 while(c<‘0‘||c>‘9‘){if(c==‘-‘) neg=-1;c=getchar();} 12 while(c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar(); 13 return x*neg; 14 } 15 16 int w[maxn][maxn]; 17 int sell[maxn][maxk],buy[maxn][maxk]; 18 int N,M,K,cnt[maxn]; 19 ll dis[maxn][maxn],d[maxn][maxn],dd[maxn]; 20 bool inq[maxn]; 21 queue<int> q; 22 23 bool spfa(int s){ 24 while(!q.empty()) q.pop(); 25 dd[s]=0;q.push(s);cnt[s]=1; 26 while(!q.empty()){ 27 int p=q.front();inq[p]=0; 28 // printf("%d %d %d ",p,cnt[p],dd[p]); 29 q.pop(); 30 for(int b=1;b<=N;b++){ 31 if(d[p][b]==-inf) continue; 32 if(dd[b]<=dd[p]+d[p][b]){ 33 dd[b]=dd[p]+d[p][b]; 34 if(inq[b]) continue; 35 if(++cnt[b]>N) return 1; 36 q.push(b); 37 inq[b]=1; 38 } 39 } 40 }return 0; 41 } 42 43 inline bool judge(ll r){ 44 // printf("%lld: ",r); 45 for(int i=1;i<=N;i++){ 46 for(int j=1;j<=N;j++) 47 d[i][j]=(dis[i][j]==-1)?-inf:w[i][j]-r*dis[i][j]; 48 } 49 bool re=0; 50 CLR(cnt,0);CLR(inq,0); 51 for(int i=1;i<=N;i++) dd[i]=-inf; 52 for(int i=1;i<=N&&!re;i++){ 53 if(!cnt[i]) re|=spfa(i); 54 } 55 return re; 56 } 57 58 int main(){ 59 //freopen("","r",stdin); 60 int i,j,k; 61 N=rd(),M=rd(),K=rd(); 62 for(i=1;i<=N;i++){ 63 for(j=1;j<=K;j++){ 64 buy[i][j]=rd(),sell[i][j]=rd(); 65 } 66 } 67 for(i=1;i<=N;i++){ 68 for(j=1;j<=N;j++){ 69 if(i==j) continue; 70 for(k=1;k<=K;k++){ 71 if(sell[j][k]==-1||buy[i][k]==-1) continue; 72 w[i][j]=max(w[i][j],sell[j][k]-buy[i][k]); 73 } 74 } 75 } 76 CLR(dis,-1); 77 for(i=1;i<=M;i++){ 78 int a=rd(),b=rd(),c=rd(); 79 dis[a][b]=c; 80 } 81 for(i=1;i<=N;i++){ 82 for(j=1;j<=N;j++){ 83 if(dis[j][i]==-1) continue; 84 for(k=1;k<=N;k++){ 85 if(dis[i][k]==-1) continue; 86 if(dis[j][k]==-1||dis[j][k]>dis[j][i]+dis[i][k]) 87 dis[j][k]=dis[j][i]+dis[i][k]; 88 } 89 } 90 } 91 // for(i=1;i<=N;i++) for(j=1;j<=N;j++) printf("%d-%d,%lld,%lld ",i,j,dis[i][j],w[i][j]); 92 93 ll l=0,r=inf,ans=0; 94 while(l<=r){ 95 int m=l+r>>1; 96 if(judge(m)) ans=m,l=m+1; 97 else r=m-1; 98 } 99 printf("%lld ",ans); 100 return 0; 101 }
以上是关于luogu3778/bzoj4898 商旅 (floyd+分数规划+spfa)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj4898[Apio2017]商旅 Floyd+分数规划+Spfa
HDU 4898 The Revenge of the Princess’ Knight (后缀数组+二分+贪心+...)