首页 > 代码库 > 分数规划

分数规划

切了三道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;
}

 

分数规划