01分数规划三类型总结
2017-01-16 08:33
113 查看
一、生成树型
给定一个带权无向图,每条边有两个权值a[i],b[i],求图的一个生成树,使得sigam(a[i])/sigam(b[i])最小.
解析:我们假设已经找到了一个解k,一个新的解比k更优
那么sigam(a[i])/sigam(b[i])<=k
即sigam(a[i])-k*sigam(b[i])<=0
sigam(a[i]-k*b[i])<=0
然后我们只需要求不等式左边的sigam(a[i]-b[i])的最小值ans,比较ans和0的关系就能判断当前解是否最优。
那么我们算法的流程就是这样了:
(1)二分一个k
(2)用新的边权a[i]-k*b[i]建图
(3)求最小生成树
(4)判断当前解是否最优
例:【jzyzoj1636】老司机飙车
现在有N个群需要张锳杰老司机的资源,为了方便表示,我们用1到N这N个数字来表示这N个群。张锳杰现在在群1,而由于网警的原因,在每个群之间传输资源都有特定的需要耗费的时间和所承担的危险,而且同一时间内资源只能在两个群之间传递。为了凸显程序员的逼格,我们将每个群在一个三维空间内以坐标的形式表示,定义两个群之间传输资源所需时间为这两个群在xOy平面内投影的直线距离,而危险则被定义为两个群第三维坐标之差。张锳杰想要单位时间内的平均危险最小,也就是传输总时间与承担的总危险的比值最低,请你帮老司机找出这个比值
二、最小割型
给定一个带权无向图,要使得从S到T没有路径相连,需要删除C条边,求这C条边的权值和sigam(vi)/C的最小值。
解析:与上题一样,我们还是假设已经找到了一个解k,那么一个更优解需要满足的条件是sigam(vi)/C<=k
即sigam(vi)-C*k<=0
sigam(vi-k)<=0
那么我们只需要求出不等式左边的最小值,判断它与0的关系就行了。
那么算法的流程如下:
(1)二分一个k值
(2)用新的边权vi-k建图
(3)跑最小割
(4)判断当前解是否最优
给定一个带权无向图,每条边有两个权值a[i],b[i],求图的一个生成树,使得sigam(a[i])/sigam(b[i])最小.
解析:我们假设已经找到了一个解k,一个新的解比k更优
那么sigam(a[i])/sigam(b[i])<=k
即sigam(a[i])-k*sigam(b[i])<=0
sigam(a[i]-k*b[i])<=0
然后我们只需要求不等式左边的sigam(a[i]-b[i])的最小值ans,比较ans和0的关系就能判断当前解是否最优。
那么我们算法的流程就是这样了:
(1)二分一个k
(2)用新的边权a[i]-k*b[i]建图
(3)求最小生成树
(4)判断当前解是否最优
例:【jzyzoj1636】老司机飙车
现在有N个群需要张锳杰老司机的资源,为了方便表示,我们用1到N这N个数字来表示这N个群。张锳杰现在在群1,而由于网警的原因,在每个群之间传输资源都有特定的需要耗费的时间和所承担的危险,而且同一时间内资源只能在两个群之间传递。为了凸显程序员的逼格,我们将每个群在一个三维空间内以坐标的形式表示,定义两个群之间传输资源所需时间为这两个群在xOy平面内投影的直线距离,而危险则被定义为两个群第三维坐标之差。张锳杰想要单位时间内的平均危险最小,也就是传输总时间与承担的总危险的比值最低,请你帮老司机找出这个比值
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #include<cmath> #include<algorithm> #include<iomanip> using namespace std; #define eps 0.0005 #define FILE "read" #define MAXN 1010 #define up(i,j,n) for(int i=j;i<=n;i++) #define dn(i,j,n) for(int i=j;i>=n;i--) namespace INIT{ char buf[1<<15],*fs,*ft; inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;} inline int read(){ int x=0,f=1; char ch=getc(); while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getc();} while(isdigit(ch)) {x=x*10+ch-'0'; ch=getc();} return x*f; } }using namespace INIT; struct node{ int x,y,h;double v; bool operator<(const node pp) const {return v<pp.v;} }e[MAXN*MAXN],E[MAXN*MAXN]; int n,len,Len,X[MAXN],Y[MAXN],V[MAXN],f[MAXN]; bool cmp(node a,node b) {return a.v<b.v;} int find(int x) {return f[x]==x?x:f[x]=find(f[x]);} void insert(int i,int j){ e[++len].x=i; e[len].y=j; e[len].v=sqrt((double)((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]))); e[len].h=abs(V[i]-V[j]); } void Insert(int x,int y,double v){E[++Len].x=x; E[Len].y=y; E[Len].v=v;} double check(double k){ Len=0; up(i,1,len) Insert(e[i].x,e[i].y,e[i].h-k*e[i].v); up(i,1,n) f[i]=i; sort(E+1,E+Len+1); double ans=0; int sum=0; up(i,1,Len){ int p=find(E[i].x),q=find(E[i].y); if(p!=q) f[p]=q,ans+=E[i].v,sum++; if(sum==n-1) break; } return ans; } int main(){ n=read(); up(i,1,n){ X[i]=read(); Y[i]=read(); V[i]=read(); up(j,1,i-1) insert(i,j); } double left=0.0001,right=10; while(left+0.0003<=right){ double mid=(left+right)/2.0; if(check(mid)<=0) right=mid; else left=mid; } double ans=check(left)?left:right; printf("%.3lf\n",ans); return 0; }
二、最小割型
给定一个带权无向图,要使得从S到T没有路径相连,需要删除C条边,求这C条边的权值和sigam(vi)/C的最小值。
解析:与上题一样,我们还是假设已经找到了一个解k,那么一个更优解需要满足的条件是sigam(vi)/C<=k
即sigam(vi)-C*k<=0
sigam(vi-k)<=0
那么我们只需要求出不等式左边的最小值,判断它与0的关系就行了。
那么算法的流程如下:
(1)二分一个k值
(2)用新的边权vi-k建图
(3)跑最小割
(4)判断当前解是否最优
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #include<cmath> #include<algorithm> #include<iomanip> using namespace std; #define FILe "read" #define INF 1000000000 #define eps 0.00001 #define MAXM 4050 #define MAXN 1050 #define up(i,j,n) for(int i=j;i<=n;i++) #define dn(i,j,n) for(int i=j;i>=n;i--) const double oo=9999999999999ll; namespace INIT{ char buf[1<<15],*fs,*ft; inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;} inline int read(){ int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } }using namespace INIT; struct node{int x,y,next,rel;double v;}e[MAXM*4]; int n,m,len,top,Link[MAXN],q[MAXN],level[MAXN],X[MAXN],Y[MAXN],V[MAXN],stack[MAXN],col[MAXN],vis[MAXN];\ bool comp(double a,double b){return abs(a-b)<eps;} void insert(int x,int y,double v){ e[++len].next=Link[x];Link[x]=len;e[len].y=y;e[len].v=v;e[len].rel=len+1; e[++len].next=Link[y];Link[y]=len;e[len].y=x;e[len].v=0;e[len].rel=len-1; } bool bfs(){ memset(level,-1,sizeof(level)); int head=0,tail=1; level[1]=0; q[1]=1; while(++head<=tail){ for(int i=Link[q[head]];i;i=e[i].next){ if(!comp(e[i].v,0)&&level[e[i].y]<0){ q[++tail]=e[i].y; level[q[tail]]=level[q[head]]+1; } } } return level >=0; } double MAXFLOW(int x,double flow){ if(x==n) return flow; double maxflow=0,d=0; for(int i=Link[x];i&&maxflow<flow;i=e[i].next){ if(level[x]+1==level[e[i].y]&&!comp(e[i].v,0)){ if(d=MAXFLOW(e[i].y,min(e[i].v,flow-maxflow))){ e[i].v-=d; e[e[i].rel].v+=d; maxflow+=d; } } } if(!maxflow) level[x]=-1; return maxflow; } double solve(){ double d,sum=0; while(bfs()) while(d=MAXFLOW(1,oo*1.0)) sum+=d; return sum; } bool check(double k){ double sum=0;len=0;top=0; memset(Link,0,sizeof(Link)); memset(vis,0,sizeof(vis)); up(i,1,m) { double temp=V[i]-k; if(temp<=0) sum+=temp,stack[++top]=i,vis[i]=1; else insert(X[i],Y[i],temp),insert(Y[i],X[i],temp); } sum+=solve(); return sum<=0; } void dfs(int x){ if(col[x]) return; col[x]=1; for(int i=Link[x];i;i=e[i].next)if(!comp(e[i].v,0)) dfs(e[i].y); } int main(){ n=read(); m=read(); up(i,1,m) X[i]=read(),Y[i]=read(),V[i]=read(); double left=1,right=1000000000; while(left+eps<right){ double mid=(left+right)/2.0; if(check(mid)) right=mid; else left=mid; } if(!check(left)) check(right); dfs(1); up(i,1,m) if(col[X[i]]!=col[Y[i]]&&!vis[i]) stack[++top]=i; printf("%d\n",top); sort(stack+1,stack+top+1); up(i,1,top) printf("%d ",stack[i]); //printf("\n%d\n",clock()); return 0; }
相关文章推荐
- 01分数规划:学习总结
- 01分数规划 总结
- 01分数规划 总结报告
- ZOJ 2676 Network Wars ★(最小割算法介绍 && 01分数规划)
- [Algorithm]01分数规划——Update:2012年7月27日
- acdream 1032 put on make up(二分01 分数规划)
- POJ 2976 01分数规划
- ZOJ 2676 01分数规划 最小割
- POJ 2728 Desert King ★(01分数规划介绍 && 应用の最优比率生成树)
- ZOJ 2676 Network Wars(01分数规划-二分+最小割)
- 01分数规划
- [Algorithm]01分数规划(转)
- pku 3621 01分数规划 sightseeing cows 解题报告
- [Algorithm]01分数规划(转)(C++代码)
- POJ 3621 Sightseeing Cows 01分数规划(参数搜索)+最短路
- 01 分数规划 poj 2976 利用二分法即可
- poj 2976(01分数规划搜索+二分答案)
- [Algorithm]01分数规划——Update:2012年7月27日
- POJ 2728 01分数规划
- POJ-2728 Desert King 最优比例生成树 01分数规划/参数搜索