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\n",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:\n",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\n",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\n",ans);
100     return 0;
101 }

 

posted @ 2018-10-13 10:33  Ressed  阅读(224)  评论(0编辑  收藏  举报