题解 CF1307G【Cow and Exercise】
CF1307G Cow and Exercise解题报告:
更好的阅读体验
题意
给定一个
分析
毒瘤线性规划对偶题,这种题不*3500天理难容/fn/fn/fn。
考虑设
根据线性规划拼凑的思想,考虑使用
此时,我们就可以其对偶形式表示出来了。
由于
这个形式仍然不是很好做,考虑将它变换成费用流的形式,即给
我们对于原图的边
而且此时存在一个优美的性质
我们不可能枚举所有的合法流量组,因此考虑建出
我们发现在最小费用最大流不断增广的时候的时候,
于是我们建图后跑出凸壳,每次查询的时候枚举凸壳所有位置并取最小值就可以了。
时间复杂度:
代码
#include<stdio.h>
#include<queue>
#include<vector>
#define inf 1000000000
using namespace std;
const int maxn=55,maxm=5005;
int n,m,Q,e,flow,cost;
int start[maxn],to[maxm],then[maxm],limit[maxm],worth[maxm],rev[maxm],dis[maxn],vis[maxn],rec[maxn];
queue<int>q;
vector< pair<int,int> >v;
inline int min(int a,int b){
return a<b? a:b;
}
inline void add(int x,int y,int z,int w,int r){
then[++e]=start[x],start[x]=e,to[e]=y,limit[e]=z,worth[e]=w,rev[e]=r;
}
inline void addedge(int x,int y,int z,int w){
add(x,y,z,w,e+2),add(y,x,0,-w,e);
}
int check(int s,int t){
for(int i=1;i<=n;i++)
dis[i]=inf,vis[i]=0;
while(!q.empty())
q.pop();
dis[s]=0,vis[s]=1,q.push(s);
while(!q.empty()){
int x=q.front();
vis[x]=0,q.pop();
for(int i=start[x];i;i=then[i]){
int y=to[i];
if(limit[i]&&dis[y]>dis[x]+worth[i]){
dis[y]=dis[x]+worth[i],rec[y]=i;
if(vis[y]==0)
vis[y]=1,q.push(y);
}
}
}
return dis[t]==inf? 0:1;
}
void work(int s,int t){
int minn=inf;
for(int i=t;i!=s;i=to[rev[rec[i]]])
minn=min(minn,limit[rec[i]]);
flow+=minn;
for(int i=t;i!=s;i=to[rev[rec[i]]])
limit[rec[i]]-=minn,limit[rev[rec[i]]]+=minn,cost+=worth[rec[i]]*minn;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,1,z);
}
while(check(1,n))
work(1,n),v.push_back(make_pair(cost,flow));
scanf("%d",&Q);
while(Q--){
int x;
double ans=1.0*inf;
scanf("%d",&x);
for(int i=0;i<v.size();i++)
ans=min(ans,1.0*(v[i].first+x)/v[i].second);
printf("%.10lf\n",ans);
}
return 0;
}