1. 程式人生 > >POJ 3621 Sightseeing Cows 最優比例環

POJ 3621 Sightseeing Cows 最優比例環

題意:

       給你L個點,P條邊,每個點和邊都有各自的權值,現在要你求一個環,使得這個環的點權/邊權最大。

做法:

       自己做當然是。。。不會做啦。。這個坑已經放在這裡很久,之前做了最優比率生成樹的,這樣三個01分數規劃的專題就算完成了。因為我們要求一個最大的val_{i}/cost_{i},那麼我們設這個比例為x,那麼我們會有一個公式f(x)=val_{i}-x*cost_{i},所以我們要二分一個最優值x,假設由這個公式出來的值是正的,那麼就說明還有一個更大的x值滿足要求,那麼就把l=mid繼續二分,否則就把r=mid。可是如果我們要判斷是否存在一個環滿足大於0有點困難,因為spfa可以判斷負環,那麼我們就可以把公式改一下,令f(x)=x*cost_{i}-val_{i},如果存在一個負環,那麼就是令l=mid;

       這裡我在寫之前一直有個疑問,不是說所有的地點只有第一次走的時候有效嗎,那為什麼每條路里面都要減掉happy[i]呢,想了一會兒,然後發現,因為每個點只能在一個環中,所以每次如果鬆弛的時候更新到這個點的話,那麼就說明還有一個更符合要求的環需要這個點了,而如果我們要這個環,那麼這個點就只會被遍歷到一次,所以才要每一條邊都要減掉happy[i]。

#include<queue>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn=3005;
const int inf=0x3f3f3f3f;
const double eps=1e-7;
int m,n,head[maxn],now,flag,vis[maxn],ct[maxn];
double dist[maxn],happy[maxn],w,maxhp,minhp,maxti,minti;
struct node{
	int to,next;
	double w;
}e[maxn*120];
void add(int u,int v,double w){
	e[now].to=v,e[now].next=head[u];
	e[now].w=w; head[u]=now++;
}
int spfa(int x,double mid){
	queue<int> q;
	dist[x]=0;
	vis[x]=1; ct[1]=1;
	q.push(x);
	while(!q.empty()){
		int u=q.front(); q.pop();
		if(++ct[u]>n) return 1;
		vis[u]=0;
		for(int i=head[u];~i;i=e[i].next){
			int t=e[i].to;
			double w=mid*e[i].w-happy[t];;
			if(dist[t]-w>dist[u]){
				dist[t]=w+dist[u];
				if(!vis[t]){
					vis[t]=1;
					q.push(t);
				}
			}
		}
	}
	return 0;
}
int ck(double mid){
    memset(ct,0,sizeof(ct));
    memset(vis,0,sizeof(vis));
    memset(dist,125,sizeof(dist));
    dist[1]=0;
    return spfa(1,mid);
}
int main(){
    int x,y;
    memset(head,-1,sizeof(head));
    maxhp=-1,maxti=-1,minhp=inf,minti=inf;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lf",&happy[i]);
        maxhp=max(maxhp,happy[i]);
        minhp=min(minhp,happy[i]);
    }
    for(int i=0;i<m;i++){
        scanf("%d%d%lf",&x,&y,&w);
        add(x,y,w);
        maxti=max(maxti,w);
        minti=min(minti,w);
    }
    double l=minhp/maxti,r=maxhp/minti,mid;
    while(r-l>eps){
        mid=(l+r)/2;
        if(ck(mid)) l=mid;
        else r=mid;
    }
    printf("%.2f\n",mid);
    return 0;
}