zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    初识Redis
    一次kafka的offset回退事件及相关知识点
    接口透传
    看懂Oracle执行计划
    Oracle中merge into的使用
    动态规划算法:0/1背包问题 (0/1 Knapsack Problem)
    动态规划算法:硬币找零(Minimum Coin Change)
    链表:按照左右半区的方式重新组合单链表
    链表:删除链表中倒数第K个节点
    链表:合并两个有序链表
  • 原文地址:https://www.cnblogs.com/Ressed/p/9782095.html
Copyright © 2011-2022 走看看