分数规划
切了三道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;
}

浙公网安备 33010602011771号