poj 2976+poj3621(01分数规划
题目:每门课有实际成绩a和总成绩b,要求去掉k门课后能得到的平均成绩的最大值。
思路:裸的分数规划题。一个非常经典的解决问题的思路就是把求值变为判定问题,然后进行2分,分数规划就是这类思想的一个应用。、
具体讲解参考此文章:http://blog.csdn.net/hhaile/article/details/8883652
/* * @author: Cwind * http://www.cnblogs.com/Cw-trip/ * 蒟蒻只能做几个水题。。 */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-3) #define IINF (1<<29) #define LINF (1ll<<59) #define FINF (1e100) #define INF 1000000000 const double pi=acos(-1.0); typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxn=1005; int n,k; double a[maxn],b[maxn]; double c[maxn]; bool check(double p){ for(int i=0;i<n;i++){ c[i]=a[i]-p*b[i]; } sort(c,c+n,greater<double>()); double sum=0; for(int i=0;i<n-k;i++){ sum+=c[i]; } if(sum<0) return 0; else return 1; } int main(){ freopen("/home/files/CppFiles/in","r",stdin); while(cin>>n>>k){ if(n==0&&k==0) break; for(int i=0;i<n;i++){ scanf("%lf",&a[i]); a[i]*=100; } for(int i=0;i<n;i++){ scanf("%lf",&b[i]); } double l=0,r=100; while(r-l>eps){ double mid=(r+l)/2; if(check(mid)){ l=mid; }else{ r=mid; } } printf("%.0f\n",l); } return 0; }
poj3621(最优比率环
题目:求一个环使得环上的点权之和比边权之和最大。
思路:把点权转移到边上,01分数规划求解。
这里用到了一个黑科技:dfs加速的spfa求找负圈,主要是先把所有dis初始化为0,然后dfs,如果遇到之前栈内的点,就是找到负圈,此算法容易实现,效率很高。
/* * @author: Cwind * http://www.cnblogs.com/Cw-trip/ * 蒟蒻只能做几个水题。。 */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-3) #define IINF (1<<29) #define LINF (1ll<<59) #define INF 1000000000 typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxn=1005; struct EDGE{ int to; double d; EDGE(int to,double d):to(to),d(d){} }; vector<EDGE> G[maxn]; int L,M; double F[maxn]; int st; int vis[maxn]; double dis[maxn]; bool dfs(int v,double p){ vis[v]=st; for(int i=0;i<G[v].size();i++){ EDGE &e=G[v][i]; if(dis[e.to]>dis[v]-F[v]+e.d*p){ dis[e.to]=dis[v]-F[v]+e.d*p; if(vis[e.to]==st) return 1; else if(dfs(e.to,p)) return 1; } } vis[v]=0; return 0; } bool check(double p){ memset(vis,0,sizeof vis); memset(dis,0,sizeof dis); for(st=1;st<=L;st++){ if(dfs(st,p)) return 1; } return 0; } int main(){ ///freopen("/home/files/CppFiles/in","r",stdin); //freopen("defense.in","r",stdin); //freopen("defense.out","w",stdout); cin>>L>>M; for(int i=1;i<=L;i++) scanf("%lf",&F[i]); for(int i=0;i<M;i++){ int a,b; double c; scanf("%d%d%lf",&a,&b,&c); G[a].pb(EDGE(b,c)); } double l=0,r=1e9; while(r-l>eps){ double mid=(r+l)/2; if(check(mid)){ l=mid; }else{ r=mid; } } printf("%.2f\n",l); return 0; }