给定一个n(2 <= n <= 1000)个点,m(2 <= m <= 5000)条边的有向图,给定每个点的点值f(i)和每条边的权值w(i),求一个环使得路径上点权和除以边权和最大。
简单来说就是最优比率生成环。
01分数规划问题,按套路二分答案。
现在问题转化为了判断可行。把边权变成\(mid*T-F\),这样可行的话一个环的和<0,问题转化成了判断负环。
而如何判断负环呢?可以记录入队次数,也可以记录最短路边数。而后一种效率更高。
时间复杂度\(O(nm\log v)\)
co int N=1e3+1,M=5e3+1;
co double eps=1e-6;
int n,m,c[N],f[N],x[M],y[M],z[M];
int Head[N],Edge[M],Next[M],tot;
double Leng[M],d[N];
bool v[N];
il void add(int x,int y,double z){
Edge[++tot]=y,Leng[tot]=z,Next[tot]=Head[x],Head[x]=tot;
}
bool judge(double w){
tot=0,memset(Head,0,sizeof Head);
for(int i=1;i<=m;++i) add(x[i],y[i],w*z[i]-f[x[i]]);
queue<int> q;
for(int i=1;i<=n;++i) q.push(i),d[i]=0,v[i]=1;
memset(c,0,sizeof c);
while(q.size()){
int x=q.front();q.pop();
v[x]=0;
for(int i=Head[x];i;i=Next[i]){
int y=Edge[i];
if(d[y]>d[x]+Leng[i]){
d[y]=d[x]+Leng[i];
if((c[y]=c[x]+1)>=n) return 1;
if(!v[y]) q.push(y),v[y]=1;
}
}
}
return 0;
}
int main(){
read(n),read(m);
for(int i=1;i<=n;++i) read(f[i]);
for(int i=1;i<=m;++i) read(x[i]),read(y[i]),read(z[i]);
double l=0,r=1000;
while(r-l>eps){
double mid=(l+r)/2;
if(judge(mid)) l=mid;
else r=mid;
}
printf("%.2f",l);
return 0;
}
幻影国建成了当今世界上最先进的高铁,该国高铁分为以下几类:
S---高速光子动力列车---时速1000km/h
G---高速动车---时速500km/h
D---动车组---时速300km/h
T---特快---时速200km/h
K---快速---时速150km/h
该国列车车次标号由上述字母开头,后面跟着一个正整数(<=1000)构成。
由于该国地形起伏不平,各地铁路的适宜运行速度不同。因此该国的每一条行车路线都由K列车次构成。例如:K=5的一条路线为:T120-D135-S1-G12-K856。当某一条路线的末尾车次与另一条路线的开头车次相同时,这两条路线可以连接起来变为一条更长的行车路线。显然若干条路线连接起来有可能构成一个环。
若有3条行车路线分别为:
x1-x2-x3
x3-x4
x4-x5-x1
x1~x5车次的速度分别为v1~v5
定义高铁环的值为(环上各条行车路线速度和)的平均值,即:
[(v1+v2+v3)+(v3+v4)+(v4+v5+v1)]/3.
所有高铁环的值的最大值称为最优高铁环的值。
给出M条行车路线,求最优高铁环的值。
第一行为行车路线条数M
接下来M行每行一条行车路线,由若干车次构成,各车次之间用‘-‘号隔开,车次的标号方式如上所述。
数据保证输入的合法性。
最优高铁环的值。四舍五入到最接近的整数。
若不存在这样的环,输出-1.
3 T120-D135-S1 S1-G12 G12-K856-T120
1283
[(200+300+1000)+(1000+500)+(500+150+200)]/3=1283
把每段行车路线的起点终点车次看成节点,则给出的就是一些边,然后要求一个01分数规划问题。
二分答案后,找负(正)环即可。
co int N=5e4+1;
co double eps=1e-3;
int n,m,st,ed,t;
int head[N],edge[N],next[N],tot;
double d[N],s[N],leng[N];
bool v[N];
il void add(int x,int y){
edge[++tot]=y,next[tot]=head[x],head[x]=tot;
}
il int f(char ch){
switch(ch){
case ‘S‘: t=0;return 1000;
case ‘G‘: t=1;return 500;
case ‘D‘: t=2;return 300;
case ‘T‘: t=3;return 200;
case ‘K‘: t=4;return 150;
}
return -1;
}
bool dfs(int x){
v[x]=1;
for(int i=head[x];i;i=next[i]){
int y=edge[i];double z=leng[i];
if(d[y]>d[x]+z){
d[y]=d[x]+z;
if(v[y]||dfs(y)) return 1;
}
}
v[x]=0;
return 0;
}
bool pd(double x){
for(int i=1;i<=m;++i) leng[i]=x-s[i];
memset(v,0,sizeof v);
memset(d,0x3f,sizeof d);
for(int i=1;i<N;++i)
if(dfs(i)) return 1;
return 0;
}
int main(){
read(m);
for(int i=1;i<=m;++i){
static char str[150];
scanf("%s",str),n=strlen(str);
int x=0;
bool flag=0;
for(int j=0;j<n;++j){
if(isdigit(str[j])) x=x*10+str[j]-‘0‘;
else if(str[j]==‘-‘){
if(!flag) st=x+t*10000;
flag=1;
x=0;
}
else s[i]+=f(str[j]);
}
ed=x+t*10000;
add(st,ed);
}
double l=0,r=0x7fffffff,ans=-1; // edit 1: -1
while(r-l>eps){
double mid=(l+r)/2;
if(pd(mid)) l=ans=mid;
else r=mid;
}
printf("%.0lf\n",ans);
return 0;
}
四川的方伯伯为了致富,决定引进海南的椰子树。方伯伯的椰子园十分现代化,椰子园中有一套独特的交通系统。
现在用点来表示交通节点,边来表示道路。这样,方伯伯的椰子园就可以看作一个有 \(n + 2\) 个交通节点,\(m\) 条边的有向无环图。\(n +1\) 号点为入口,\(n +2\) 号点为出口。每条道路都有六个参数,\(u_i, v_i, a_i, b_i, c_i, d_i\),分别表示,该道路从 \(u_i\) 号点通向 \(v_i\) 号点,将它的容量压缩一次要 \(a_i\) 的花费,容量扩大一次要 \(b_i\) 的花费,该条道路当前的运输容量上限为 \(c_i\),并且每单位运输量通过该道路要 \(d_i\) 的费用。
在这个交通网络中,只有一条道路与起点相连。因为弄坏了这条道路就会导致整个交通网络瘫痪,聪明的方伯伯决定绝不对这条道路进行调整,也就是说,现在除了这条道路之外,对其余道路都可以进行调整。
有两种调整方式:
一条道路可以被多次调整。
由于很久以前,方伯伯就请过一个工程师,对这个交通网络进行过一次大的优化调整。所以现在所有的道路都被完全的利用起来了,即每条道路的负荷都是满的(每条道路的流量等于其容量)。但方伯伯一想到自己的海南椰子会大丰收,就十分担心巨大的运输量下,会导致过多的花费。因此,方伯伯决定至少进行一次调整,调整之后,必须要保持每条道路满负荷,且总交通量不会减少。
设调整后的总费用是 \(Y\),调整之前的总费用是 \(X\)。现在方伯伯想知道,最优调整比率是多少,即假设他进行了 \(k\) 次调整,\((X - Y)/k\) 最大能是多少?
注:总费用 = 交通网络的运输花费 + 调整的花费
对于所有数据,\(1 \leq N \leq 5000,\ 0 \leq M \leq 3000,\ 1 \leq U_i,V_i \leq N+2,\ 0 \leq A_i,B_i \leq 500,\ 0 \leq C_i \leq 10000,\ 0 \leq D_i \leq 1000\)。
一个可以增容和减容的网络流图?
由于要满流,所以减容操作的花费是\(a_i-d_i\),增容操作的花费是\(b_i+d_i\)。
01分数规划,二分答案\(\text{mid}\)。
起点出边不能变,所以总流量不会变。那么增加的流量和减少的流量抵消了。
有向无环图,所以改的应该是个“环”?\(Y-X+k\cdot \text{mid}\leq 0\),所以找的应该是负环。
负环要把所有点都放进去……
CO int N=5e3+10;
CO float128 inf=1e18;
struct edge {int y,w;};
vector<edge> to[N];
float128 dis[N];
int vis[N],cnt[N];
int main(){
int n=read<int>();
for(int m=read<int>();m--;){
int x=read<int>(),y=read<int>();
int a=read<int>(),b=read<int>(),c=read<int>(),d=read<int>();
to[x].push_back({y,b+d});
if(c) to[y].push_back({x,a-d});
}
float128 L=0,R=1e9;
for(int t=1;t<=40;++t){
float128 mid=(L+R)/2;
function<bool()> check=[&]()->bool{
deque<int> que;
for(int i=1;i<=n+2;++i){
dis[i]=0,cnt[i]=0;
que.push_back(i),vis[i]=1;
}
while(que.size()){
int x=que.front();
que.pop_front(),vis[x]=0;
for(CO edge&e:to[x])if(dis[e.y]>dis[x]+e.w+mid){
dis[e.y]=dis[x]+e.w+mid;
if((cnt[e.y]=cnt[x]+1)>=n) return 1;
if(!vis[e.y]) que.push_back(e.y),vis[e.y]=1;
}
}
return 0;
};
check()?L=mid:R=mid;
}
printf("%.2Lf\n",L);
return 0;
}
POJ3621 Sightseeing Cows 和 CH6B12 最优高铁环 和 SCOI2014 方伯伯运椰子
原文:https://www.cnblogs.com/autoint/p/10944348.html