01分數規劃的兩道例題
POJ 2728 Desert King 最優比率生成樹
title
wrong reason
使用printf不論是進行double輸出還是float輸出都要用%.3f。
查了半天,終於找到了原因:POJ就是個牛la逼ji玩意兒。
問:有人告訴我不能在printf中使用%lf。為什麼printf()用%f輸出double型,而scanf卻用%lf呢?
答:printf的%f說明符的確既可以輸出float型又可以輸出double型。根據“預設引數提升”規則(在printf這樣的函式的可變引數列表中,不論作用域內有沒有原型,都適用這一規則)float型會被提升為double型。因此printf()只會看到雙精度數。參見問題15.2。
(嚴格地講,%lf在printf下是未定義的,但是很多系統可能會接受它。要確保可移植性,就要堅持使用%f。)
轉自qu317058542_scu
analysis
好了,言歸正傳,開始分析一下這道題。
首先,解釋一下,歐幾里得距離是個什麼東西:在數學中,歐幾里得距離或歐幾里得度量是歐幾里得空間中兩點間“普通”(即直線)距離。——摘自某度。
其實原題就是求 ,對每個生成樹,設其比率,可得
那麼對於所有的生成樹,顯然,當 時,等號成立。
而我們現在不知道是多少,只好進行列舉,對每個列舉的r ,構建新的權值(),然後求最小生成樹, 為什麼求最小呢?
我的理解就是這是為了尋找使得生成樹的總權值為0的可能性,因為只有當其等於0 的時候,才滿足了條件1 這個條件, 說明這個是可行的,並且如果列舉到值為時,其最小生成樹的的總權值必然恰好等於0,但是如果不能等於0, 比如大於0, 顯然是對該r值,所有的生成樹上無論如何也滿足不了條件1,說明值就是偏小了。同理如果小於0,值是偏大的,說明可能存在某些生成樹使得滿足條件1,而我們的目標是在滿足條件1的情況下使得最小,摘自sdj。
code
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=1006,inf=0x3f3f3f3f;
const double eps=1e-6;
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch)) ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
int n;
struct mst
{
int x,y,z;
}e[maxn];
double a[maxn][maxn],b[maxn][maxn],c[maxn][maxn],d[maxn];
bool v[maxn];
inline double s(int i,int j)
{
return sqrt((e[i].x-e[j].x) * (e[i].x-e[j].x) + (e[i].y-e[j].y) * (e[i].y-e[j].y));
}
inline double check(double k)
{
for (int i=1;i<=n;++i)
for (int j=i;j<=n;++j)
if (i==j) c[i][j]=inf;
else c[i][j]=c[j][i]=a[i][j]-k*b[i][j];
memset(v,0,sizeof(v));
for (int i=1;i<=n;++i)
d[i]=inf;
d[1]=0;
double ans=0;
while (1)
{
int x=0;
for (int i=1;i<=n;++i)
if (!v[i] && (!x || d[x]>d[i]))
x=i;
if (!x) break;
v[x]=1;
ans+=d[x];
for (int i=1;i<=n;++i)
d[i]=min(d[i],c[x][i]);
}
return ans;
}
inline void Desert_King()
{
for (int i=1;i<=n;++i)
read(e[i].x),read(e[i].y),read(e[i].z);
double num=0;
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
{
num+=(a[i][j]=a[j][i]=abs(e[i].z-e[j].z));
b[i][j]=b[j][i]=s(i,j);
}
double l=0,r=num;
while (l+eps<=r)
{
double mid=(l+r)/2;
if (check(mid)>=0) l=mid;
else r=mid;
}
printf("%.3f\n",l);
}
int main()
{
while (cin>>n && n) Desert_King();
return 0;
}
「BZOJ1690」[Usaco2007 Dec] 奶牛的旅行 最優比率環
titlep1938
描述 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 Format
第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 Format
輸出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
輸出說明:
如果奶牛選擇1 -> 2 -> 3 -> 5 -> 1的旅行路線,她們能得到的總樂趣值為60,為此她們得花費10單位的時間在走路上。於是她們在這次旅行中的平均樂趣值為6。如果她們走2 -> 3 -> 5 -> 2的路線,就只能得到30/6 = 5的平均樂趣值。並且,任何去參觀建築物4的旅行路線的平均樂趣值都沒有超過4。
時間限制 Time Limitation
1s
註釋 Hint
來源 Source
usaco 2007 dec gold sightsee
wrong reason
spfa函式的傳參型別錯誤的設成了int,害我一直WA。
analysis
首先要證明的是奶牛最後選到一定是一個簡單環,如下,
假設最優解不是簡單環,則其中必定有一個重複點,設為c1,對於這個點隔開到也是兩個環,我們設兩個環中除了這個點其他點權值和分別為,c2,c3;邊權值為 a1,s2;
由於它是最優解所以有 :
顯然錯誤,至此可以有結論,最優解必定是簡單環
基於這個結論在思考,發現如果判斷某個解是否行,我們考慮的是簡單環!!因為如果存在這樣一個簡單環則顯然成立,不存在則必定不可行;所以我們可以把邊權值變成, mid*t-F[to],如果存在負權環則mid是可行解。
綜上發現2分答案+判負環是正確解法,摘自lzqxh
code
/*******************************************************
Problem: 3621 User: sjh2021
Memory: 708K Time: 532MS
Language: G++ Result: Accepted
********************************************************/
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=1001,maxm=5005;
const double eps=1e-3;
template<typename T>inline void read(T &x)
{
x=0;
T f=1,ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
int n,m,happy[maxn];
int ver[maxm],edge[maxm],Next[maxm],head[maxn],len;
inline void add(int x,int y,int z)
{
ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
double dist[maxn];
int v[maxn],cnt[maxn];
inline bool spfa(double k)
{
memset(cnt,0,sizeof(cnt));
memset(v,0,sizeof(v));
for (int i=1;i<=n;++i)
dist[i]=1e15;
queue<int>q;
dist[1]=0,v[1]=1;
q.push(1),++cnt[1];
while (!q.empty())
{
int x=q.front();
q.pop();
v[x]=0;
for (int i=head[x];i;i=Next[i])
{
int y=ver[i],z=edge[i];
if (dist[y]>dist[x]+k*z-happy[x])
{
dist[y]=dist[x]+k*z-happy[x];
if (!v[y])
{
q.push(y),v[y]=1;
if (++cnt[y]>n) return true;
}
}
}
}
return false;
}
int main()
{
read(n);read(m);
for (int i=1;i<=n;++i)
read(happy[i]);
for (int i=1;i<=m;++i)
{
int x,y,z;
read(x);read(y);read(z);
add(x,y,z);
}
double l=0,r=10000;
while (l+eps<r)
{
double mid=(l+r)/2;
if (spfa(mid)) l=mid;
else r=mid;
}
printf("%.2f\n",l);
return 0;
}
放一個以前寫的1000MS過得程式碼。碼風有點不一樣
/******************************************
Problem: 3621 User: sjh2021
Memory: 1308K Time: 1000MS
Language: G++ Result: Accepted
*******************************************/
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
#define _ 100010
using namespace std;
const double eps=1e-8;
struct rec
{
int x,y,z;
}e[_];
inline int read()
{
int f=1,num=0;
char ch=getchar();
while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
while (ch>='0'&&ch<='9') num=(num<<1)+(num<<3)+ch-'0',ch=getchar();
return num*f;
}
int n,m,happy[_];
int ver[_],Next[_],head[_],len;
double edge[_],l,r;
void add(int x,int y,double z)
{
ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
double dist[_];
bool v[_];
int cnt[_];
queue<int>q;
inline bool spfa()
{
for (int i=1;i<=n;++i) dist[i]=-1e9;
memset(cnt,0,sizeof(cnt));
memset(v,0,sizeof(v));
dist[1]=0;
q.push(1);
while (!q.empty())
{
int x=q.front();
q.pop();
v[x]=0;
for (int i=head[x];i;i=Next[i])
{
int y=ver[i];
double z=edge[i];
if (dist[y]+eps<dist[x]+z)
{
dist[y]=dist[x]+z;
if (!v[y])
{
q.push(y),v[y]=1;
if (++cnt[y]>n) return true;
}
}
}
}
return false;
}
inline bool check(double v)
{
memset(head+1,0,sizeof(int)*n);
len=0;
for (int i=1;i<=m;++i)
add(e[i].x,e[i].y,happy[e[i].x]-e[i].z*v);
if (spfa()) return true;
else return false;
}
int main()
{
n=read(),m=read();
for (int i=1;i<=n;++i)
happy[i]=read();
for (int i=1;i<=m;++i)
{
int x=read(),y=read(),z=read();
e[i]=(rec){x,y,z};
r+=z;
}
while (l+eps<r)
{
double mid=(l+r)/2.0;
if (check(mid)) l=mid;
else r=mid;
}
printf("%.2f",l);
return 0;
}
相關文章
- 非線性規劃的經典例題--選址問題
- 元規劃:使用規劃器解決數學問題
- 動態規劃---例題3.最大子段和問題動態規劃
- 醜數問題——動態規劃、Java動態規劃Java
- 動態規劃之數的劃分動態規劃
- 01 分數規劃
- 01分數規劃
- 如何使得 unittest 的測試用例有序規劃?
- 每日一道演算法題:1.兩數之和演算法
- 尤拉計劃714:兩種數位的數
- 動態規劃演算法理解——從例題中學習動態規劃演算法
- 我的動態規劃題單動態規劃
- 雜題隨筆 10.31 兩道LIS相關的題
- 動態規劃題單動態規劃
- 好題——動態規劃動態規劃
- 動態規劃專題動態規劃
- 「分數規劃」學習筆記及做題記錄筆記
- 從兩道面試題說起面試題
- 一道看完答案你會覺得很沙雕的「動態規劃演算法題」動態規劃演算法
- 分數規劃P3199
- 動態規劃練習題動態規劃
- 動態規劃做題思路動態規劃
- 動態規劃解題方法動態規劃
- leetcode題解(動態規劃)LeetCode動態規劃
- 2024/9/10+11 分塊雜題三道 + 縫合題兩道
- 一道數學題的解法
- 每日一道 LeetCode (1):兩數之和LeetCode
- 動態規劃(介紹閆氏dp分析法及相關例題分析)動態規劃
- 每天一道演算法題:求兩個排序陣列的中位數演算法排序陣列
- Python小白的數學建模課-04.整數規劃Python
- 分數規劃學習筆記筆記
- c++ 動態規劃(數塔)C++動態規劃
- matlab求解線性規劃問題Matlab
- 做題記錄 --- 動態規劃動態規劃
- 動態規劃 擺花 題解動態規劃
- 【動態規劃】揹包問題動態規劃
- 動態規劃之子序列問題動態規劃
- 揹包問題----動態規劃動態規劃