题解:首先肯定要跑最短路,而n<=100,所以可以用floyd,然后根据比值,很容易想到二分答案,然后再SPFA跑一遍负环,就能求出解了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=107; int n,m,p,B[N][1007],S[N][1007],val[N][N],cnt[N]; ll d[N][N],dis[N]; bool vis[N]; queue<int>q; bool check(int mid) { while(!q.empty())q.pop(); for(int i=1;i<=n;i++)dis[i]=0,vis[i]=1,cnt[i]=1,q.push(i); while(!q.empty()) { int u=q.front();q.pop(); for(int i=1;i<=n;i++) if(i!=u&&d[u][i]<1e9&&dis[i]<=dis[u]+val[u][i]-1ll*d[u][i]*mid) { dis[i]=dis[u]+val[u][i]-1ll*d[u][i]*mid; if(!vis[i]) { vis[i]=1,q.push(i),cnt[i]++; if(cnt[i]>n)return 1; } } vis[u]=0; } return 0; } int main() { scanf("%d%d%d",&n,&m,&p); for(int i=1;i<=n;i++) for(int j=1;j<=p;j++) scanf("%d%d",&B[i][j],&S[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=p;k++) if(B[i][k]!=-1&&S[j][k]!=-1) val[i][j]=max(val[i][j],S[j][k]-B[i][k]); for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)d[i][j]=i==j?0:1e9; for(int i=1,x,y,z;i<=m;i++)scanf("%d%d%d",&x,&y,&z),d[x][y]=z; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) d[i][j]=min(d[i][j],d[i][k]+d[k][j]); int l=0,r=1e9,ans=0; while(l<=r) { int mid=l+r>>1; if(check(mid))ans=mid,l=mid+1;else r=mid-1; } printf("%d",ans); }