分数规划
切了三道01分数规划的题目,特来总结;
[分数规划]老司机飙车
大致题意是求最小比率生成树;
经过数学变形化为二分的最小生成树问题;
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<ctime> #include<cstdlib> #include<iomanip> using namespace std; #define LL long long #define up(i,j,n) for(int i=(j);i<=(n);i++) #define FILE "dealing" const int maxn=1010,inf=10; const double eps=0.0005; int n; int x[maxn],y[maxn],z[maxn]; double d[maxn][maxn],Dan[maxn][maxn]; int read(){ int x=0,f=1,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f*x; } struct node{ int x,y; double v; bool operator<(const node& b)const{return v<b.v;} }e[maxn*maxn]; int len=0; int fa[maxn]; int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);} bool Kruskal(){ int fx,fy; double sum=0; up(i,1,n)fa[i]=i; sort(e+1,e+len+1); up(i,1,len){ fx=getfa(e[i].x); fy=getfa(e[i].y); if(fx!=fy)fa[fx]=fy,sum+=e[i].v; } if(sum<0)return 1; return 0; } int squ(int x){return x*x;} int main(){ n=read(); up(i,1,n)x[i]=read(),y[i]=read(),z[i]=read(); up(i,1,n)up(j,i+1,n){ Dan[i][j]=sqrt(1.0*squ(x[i]-x[j])+squ(y[i]-y[j])); d[i][j]=abs(z[i]-z[j]); } double left=0,right=inf; while(right-left>=eps){ double mid=(left+right)/2; len=0; up(i,1,n)up(j,i+1,n)e[++len].x=i,e[len].y=j,e[len].v=d[i][j]-mid*Dan[i][j]; if(Kruskal())right=mid; else left=mid; } printf("%.3lf\n",left); return 0; }
[分数规划]必须切断与文化课的连接
大致意思是求最小密度割(使割的总权值除以割边的数目最小)
二分后,构造新图,负权边直接选中,正权边进行最小割,加起来,验证是否可行;
#include<iostream> #include<cstdio> #include<cstring> #include<ctime> #include<cstdlib> #include<cmath> #include<algorithm> #include<iomanip> using namespace std; #define LL long long #define up(i,j,n) for(int i=(j);i<=(n);i++) #define FILE "dealing" int read(){ int f=1,x=0,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return f*x; } const int maxn=2010,inf=100000000; const double eps=0.001; int n,m,s,t; struct node{ int y,next,rev; double flow; }e[maxn]; int linkk[maxn],len=0; int x[maxn],y[maxn]; double v[maxn]; bool cmp(double x,double y){return abs(x-y)<=eps;} void insert(int x,int y,double flow){ e[++len].y=y; e[len].flow=flow; e[len].rev=len+1; e[len].next=linkk[x]; linkk[x]=len; e[++len].y=x; e[len].flow=0; e[len].next=linkk[y]; linkk[y]=len; e[len].rev=len-1; } int q[maxn],tail=0,head=0,d[maxn]; bool makelevel(){ tail=head=0; memset(d,10,sizeof(d)); q[++tail]=s;int x; d[s]=0; while(++head<=tail){ x=q[head]; for(int i=linkk[x];i;i=e[i].next) if(d[e[i].y]>inf&&!cmp(e[i].flow,0))d[e[i].y]=d[x]+1,q[++tail]=e[i].y; } return d[t]<inf; } double makeflow(int x,double flow){ if(x==t)return flow; double dis,maxflow=0; for(int i=linkk[x];i&&maxflow<flow&&!cmp(maxflow,flow);i=e[i].next){ if(!cmp(e[i].flow,0)&&d[e[i].y]==d[x]+1) if(dis=makeflow(e[i].y,min(flow-maxflow,e[i].flow))){ maxflow+=dis; e[i].flow-=dis; e[e[i].rev].flow+=dis; } } if(maxflow<=eps&&maxflow>=eps)d[x]=-1; return maxflow; } double dinic(){ double d,ans=0; while(makelevel()) while(d=makeflow(s,inf)) ans+=d; return ans; } int que[maxn],cnt=0,vis[maxn],w[maxn],Cnt=0; void dfs(int o){ vis[o]=1; for(int i=linkk[o];i;i=e[i].next) if(!vis[e[i].y]&&!cmp(e[i].flow,0))dfs(e[i].y); } int main(){ n=read(),m=read();s=1,t=n; up(i,1,m)x[i]=read(),y[i]=read(),v[i]=read(); double left=0,right=inf; while(right-left>=eps){ double mid=(left+right)/2,sum=0; len=0; memset(linkk,0,sizeof(linkk)); up(i,1,m){ if(v[i]-mid<=0)sum+=(v[i]-mid); else insert(x[i],y[i],v[i]-mid),insert(y[i],x[i],v[i]-mid); } sum+=dinic(); if(sum<=0)right=mid; else left=mid; } up(i,1,m)if(v[i]-left<0)que[++cnt]=i; dfs(s); up(i,1,n)if(!vis[i]) up(j,1,m)if((x[j]==i&&vis[y[j]])||(y[j]==i&&vis[x[j]]))que[++cnt]=j; sort(que+1,que+cnt+1); up(i,1,cnt) if(que[i]!=que[i-1])w[++Cnt]=que[i]; printf("%d\n",Cnt); up(i,1,Cnt)printf("%d\n",w[i]); return 0; }
[分数规划]炉石传说校队(为什么都是些奇奇怪怪的名字?)
大致题意是求最大密度子图;
详见胡伯涛论文;
#include<iostream> #include<cstdio> #include<cstring> #include<ctime> #include<cstdlib> #include<cmath> #include<algorithm> #include<iomanip> using namespace std; #define LL long long #define up(i,j,n) for(int i=(j);i<=(n);i++) #define FILE "dealing" int read(){ int f=1,x=0,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return f*x; } const int maxn=2010,inf=100000000; const double eps=0.001; int n,m,s,t; struct node{ int y,next,rev; double flow; }e[maxn]; int linkk[maxn],len=0; int x[maxn],y[maxn]; double v[maxn]; bool cmp(double x,double y){return abs(x-y)<=eps;} void insert(int x,int y,double flow){ e[++len].y=y; e[len].flow=flow; e[len].rev=len+1; e[len].next=linkk[x]; linkk[x]=len; e[++len].y=x; e[len].flow=0; e[len].next=linkk[y]; linkk[y]=len; e[len].rev=len-1; } int q[maxn],tail=0,head=0,d[maxn]; bool makelevel(){ tail=head=0; memset(d,10,sizeof(d)); q[++tail]=s;int x; d[s]=0; while(++head<=tail){ x=q[head]; for(int i=linkk[x];i;i=e[i].next) if(d[e[i].y]>inf&&!cmp(e[i].flow,0))d[e[i].y]=d[x]+1,q[++tail]=e[i].y; } return d[t]<inf; } double makeflow(int x,double flow){ if(x==t)return flow; double dis,maxflow=0; for(int i=linkk[x];i&&maxflow<flow&&!cmp(maxflow,flow);i=e[i].next){ if(!cmp(e[i].flow,0)&&d[e[i].y]==d[x]+1) if(dis=makeflow(e[i].y,min(flow-maxflow,e[i].flow))){ maxflow+=dis; e[i].flow-=dis; e[e[i].rev].flow+=dis; } } if(maxflow<=eps&&maxflow>=eps)d[x]=-1; return maxflow; } double dinic(){ double d,ans=0; while(makelevel()) while(d=makeflow(s,inf)) ans+=d; return ans; } int que[maxn],cnt=0,vis[maxn],w[maxn],Cnt=0; void dfs(int o){ vis[o]=1; for(int i=linkk[o];i;i=e[i].next) if(!vis[e[i].y]&&!cmp(e[i].flow,0))dfs(e[i].y); } int main(){ n=read(),m=read();s=1,t=n; up(i,1,m)x[i]=read(),y[i]=read(),v[i]=read(); double left=0,right=inf; while(right-left>=eps){ double mid=(left+right)/2,sum=0; len=0; memset(linkk,0,sizeof(linkk)); up(i,1,m){ if(v[i]-mid<=0)sum+=(v[i]-mid); else insert(x[i],y[i],v[i]-mid),insert(y[i],x[i],v[i]-mid); } sum+=dinic(); if(sum<=0)right=mid; else left=mid; } up(i,1,m)if(v[i]-left<0)que[++cnt]=i; dfs(s); up(i,1,n)if(!vis[i]) up(j,1,m)if((x[j]==i&&vis[y[j]])||(y[j]==i&&vis[x[j]]))que[++cnt]=j; sort(que+1,que+cnt+1); up(i,1,cnt) if(que[i]!=que[i-1])w[++Cnt]=que[i]; printf("%d\n",Cnt); up(i,1,Cnt)printf("%d\n",w[i]); return 0; }