1. 程式人生 > >【bzoj1690/Usaco2007 Dec】奶牛的旅行——分數規劃 最優比率環

【bzoj1690/Usaco2007 Dec】奶牛的旅行——分數規劃 最優比率環

splay ++ 開車 小數 單位 固定 i+1 ros 農場

Description

作為對奶牛們辛勤工作的回報,Farmer John決定帶她們去附近的大城市玩一天。旅行的前夜,奶牛們在興奮地討論如何最好地享受這難得的閑暇。 很幸運地,奶牛們找到了一張詳細的城市地圖,上面標註了城市中所有L(2 <= L <= 1000)座標誌性建築物(建築物按1..L順次編號),以及連接這些建築物的P(2 <= P <= 5000)條道路。按照計劃,那天早上Farmer John會開車將奶牛們送到某個她們指定的建築物旁邊,等奶牛們完成她們的整個旅行並回到出發點後,將她們接回農場。由於大城市中總是寸土寸金,所有的道路都很窄,政府不得不把它們都設定為通行方向固定的單行道。 盡管參觀那些標誌性建築物的確很有意思,但如果你認為奶牛們同樣享受穿行於大城市的車流中的話,你就大錯特錯了。與參觀景點相反,奶牛們把走路定義為無趣且令她們厭煩的活動。對於編號為i的標誌性建築物,奶牛們清楚地知道參觀它能給自己帶來的樂趣值F_i (1 <= F_i <= 1000)。相對於奶牛們在走路上花的時間,她們參觀建築物的耗時可以忽略不計。 奶牛們同樣仔細地研究過城市中的道路。她們知道第i條道路兩端的建築物 L1_i和L2_i(道路方向為L1_i -> L2_i),以及她們從道路的一頭走到另一頭所需要的時間T_i(1 <= T_i <= 1000)。 為了最好地享受她們的休息日,奶牛們希望她們在一整天中平均每單位時間內獲得的樂趣值最大。當然咯,奶牛們不會願意把同一個建築物參觀兩遍,也就是說,雖然她們可以兩次經過同一個建築物,但她們的樂趣值只會增加一次。順便說一句,為了讓奶牛們得到一些鍛煉,Farmer John要求奶牛們參觀至少2個建築物。 請你寫個程序,幫奶牛們計算一下她們能得到的最大平均樂趣值。

Input

* 第1行: 2個用空格隔開的整數:L 和 P

* 第2..L+1行: 第i+1行僅有1個整數:F_i * 第L+2..L+P+1行: 第L+i+1行用3個用空格隔開的整數:L1_i,L2_i以及T_i, 描述了第i條道路。

Output

* 第1行: 輸出1個實數,保留到小數點後2位(直接輸出,不要做任何特殊的取 整操作),表示如果奶牛按題目中描述的一系列規則來安排她們的旅 行的話,她們能獲得的最大平均樂趣值

Sample Input

5 7
30
10
10
5
10
1 2 3
2 3 2
3 4 5
3 5 2
4 5 5
5 1 3

5 2 2

Sample Output

6.00
分析: 首先分析最優解必然為一個單獨的環(一定不會是環套環),為什麽?我不知道,自己推一下吧...... 這樣的話我們把邊的利潤定義為邊指向的點i的利潤e[i],把邊的代價定義為指向的那個點的代價v[i],每個點選或不選的情況定義為x[i]。 這樣就把利潤和代價都放在了邊上。 定義一個函數f(l)=l*sigma(v[i]*x[i])-sigma(e[i]*x[i])=sigma((l*v[i]-e[i])*x[i]),令d[i]=l*v[i]-e[i]。 當f(l)<0時,l*sigma(v[i]*x[i])-sigma(e[i]*x[i])<0,即sigma(e[i]*x[i])/sigma(v[i]*x[i])>l,表明當前的選取方式能得到比當前l更大的解;
當f(l)>0時,此時的解沒有l優。 因此最優的情況就是f(l)=0,此時d[i]=0,易知d[i]隨l的增大而增大,所以可以二分l直到d[i]=0,此時的l就是最優解。 註意是有向邊,判斷的話可以用類似於SPFA判負環那樣的操作,具體實現看代碼吧: 技術分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define mem(a) memset(a,0,sizeof(a))
 5 const int N=1005,P=5005;
 6 const double eps=1e-7;
 7 int n,m,tot=0,first[N],a[N];
 8 double d[N];
 9 bool flag,ok[N];
10 struct node{
11     int ne,to,w;
12     double v;
13 }e[P*2];
14 int read(){
15     int ans=0,f=1;char c=getchar();
16     while(c<0||c>9){if(c==-)f=-1;c=getchar();}
17     while(c>=0&&c<=9){ans=ans*10+c-48;c=getchar();}
18     return ans*f;
19 }
20 void add(int u,int v,int w){
21     e[++tot]=(node){first[u],v,w,0};first[u]=tot;
22 }
23 void dfs(int x){
24     ok[x]=1;
25     for(int i=first[x];i;i=e[i].ne){
26         int to=e[i].to;
27         if(d[to]>d[x]+e[i].v){
28             if(ok[to]){flag=1;return;}
29             d[to]=d[x]+e[i].v;
30             dfs(to);
31         }
32     }
33     ok[x]=0;
34 }
35 bool check(double x){
36     flag=0;
37     for(int i=1;i<=n;i++)ok[i]=d[i]=0;
38     for(int i=1;i<=n;i++){dfs(i);if(flag)return 1;}
39     return 0;
40 }
41 int main(){
42     n=read();m=read();
43     for(int i=1;i<=n;i++)a[i]=read();
44     for(int j=1,uu,vv,z;j<=m;j++){
45         uu=read();vv=read();z=read();
46         add(uu,vv,z);
47     }
48     double l=0,r=1000.0,mid;
49     while(r-l>eps){
50         mid=(l+r)/2.0;
51         for(int i=1;i<=n;i++){
52         for(int j=first[i];j;j=e[j].ne){
53             e[j].v=mid*e[j].w-a[e[j].to];
54         }
55     }
56         if(check(mid))l=mid;
57         else r=mid;
58     }
59     printf("%.2f",mid);
60     return 0;
61 }
bzoj1690

【bzoj1690/Usaco2007 Dec】奶牛的旅行——分數規劃 最優比率環