您的位置:首页 > 其它

IndiaHacks 2016 - Online Edition (CF) . D

2016-03-20 13:16 375 查看
这题思路很简单,二分m,求最大流是否大于等于x。

但是比赛过程中大部分的代码都被hack了。。。

精度问题,和流量可能超int

关于精度问题,这题真是提醒的到位,如果是先用二分将精度控制在10^-8左右,最后乘一个10^4,精度只能在10-4,而二分控制精度在10^-11很容易死循环(因为double 保存15-16位有效数字,结果可能为10^6级,精确到10-11,double做不到)

所以这题二分可以不写成while(d-b>eps),而直接规定二分的次数,设置成100次,基本可以保证14-15位有效数字都正确了,这时再乘10^4还是能够达到题目中要求的10^-6的精度。

还有一种处理精度的方法:

直接定义上下界就为输出的最后结果,在判断的过程中除以x,最后输出也能满足要求。

第一种精度处理方式:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <math.h>
#include <iostream>
using namespace std;
#define eps 1e-11
#define N 55
#define M 500500
#define INF 0x3fffff

struct node1
{
long long to,w,next;
}edge[M];

long long sn,sm,sx;
long long pre[10*N];
long long g

;
long long gap[10*N],lv[10*N];
long long k,c,m;
long long cnt;
long long n,nn;
long long s,t;
long long ans;
long long sum;

void add_edge(long long u,long long v,long long w)
{
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].next=pre[u];
pre[u]=cnt++;
}

long long gdfs(long long k,long long w)
{
if(k==t) return w;
long long f=0;
long long mi=nn-1;
for(long long p=pre[k];p!=-1;p=edge[p].next)
{
long long v=edge[p].to,tw=edge[p].w;
if(tw!=0)
{
if(lv[k]==lv[v]+1)
{
long long tmp=gdfs(v,min(tw,w-f));
f+=tmp;
edge[p].w-=tmp;
edge[p^1].w+=tmp;
if(f==w||lv[s]==nn) break;
}
if(lv[v]<mi) mi=lv[v];
}
}
if(f==0)
{
gap[lv[k]]--;
if( gap[ lv[k] ]==0 )
{
lv[s]=nn;
}
lv[k]=mi+1;
gap[lv[k]]++;
}
return f;
}

long long sap()
{
memset(lv,0,sizeof(lv));
memset(gap,0,sizeof(gap));
gap[0]=nn;
while(lv[s]<nn)
{
sum+=gdfs(s,INF);
}
return sum;
}

long long a[505],b[505],kk[505];

long long check(double mid)
{
sum=0;
//mid/=sx;
memset(pre,-1,sizeof(pre));
cnt=0;

for(long long i=0;i<sm;i++)
{
add_edge(a[i],b[i],(long long)(kk[i]/mid+eps));
add_edge(b[i],a[i],0);
}
if(sap()>=sx)
{
return 1;
}
else return 0;
}

int main()
{
cin>>sn>>sm>>sx;
for(long long i=0;i<sm;i++)
{
cin>>a[i]>>b[i]>>kk[i];
}

s=1;
t=sn;
nn=t+1;

//这个精度问题还是很坑。。。
double b=0,d=10000000.0;
//好坑的东西! 我就操!
int time=160;
while(time--)//这里精度太小,竟然会死循环。。。
{
double mid=(b+d)/2;
if( check(mid)==1 )
{
b = mid;
}
else
{
d = mid;
}
}
printf("%.10lf",b*sx);
return 0;
}


第二种精度处理方式:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <math.h>
#include <iostream>
using namespace std;
#define eps 1e-11
#define N 55
#define M 500500
#define INF 0x3fffff

struct node1
{
long long to,w,next;
}edge[M];

long long sn,sm,sx;
long long pre[10*N];
long long g

;
long long gap[10*N],lv[10*N];
long long k,c,m;
long long cnt;
long long n,nn;
long long s,t;
long long ans;
long long sum;

void add_edge(long long u,long long v,long long w)
{
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].next=pre[u];
pre[u]=cnt++;
}

long long gdfs(long long k,long long w)
{
if(k==t) return w;
long long f=0;
long long mi=nn-1;
for(long long p=pre[k];p!=-1;p=edge[p].next)
{
long long v=edge[p].to,tw=edge[p].w;
if(tw!=0)
{
if(lv[k]==lv[v]+1)
{
long long tmp=gdfs(v,min(tw,w-f));
f+=tmp;
edge[p].w-=tmp;
edge[p^1].w+=tmp;
if(f==w||lv[s]==nn) break;
}
if(lv[v]<mi) mi=lv[v];
}
}
if(f==0)
{
gap[lv[k]]--;
if( gap[ lv[k] ]==0 )
{
lv[s]=nn;
}
lv[k]=mi+1;
gap[lv[k]]++;
}
return f;
}

long long sap()
{
memset(lv,0,sizeof(lv));
memset(gap,0,sizeof(gap));
gap[0]=nn;
while(lv[s]<nn)
{
sum+=gdfs(s,INF);
}
return sum;
}

long long a[505],b[505],kk[505];

long long check(long double mid)
{
sum=0;
mid/=sx;
memset(pre,-1,sizeof(pre));
cnt=0;

for(long long i=0;i<sm;i++)
{
add_edge(a[i],b[i],(long long)(kk[i]/mid+eps));
add_edge(b[i],a[i],0);
}
if(sap()>=sx)
{
return 1;
}
else return 0;
}

int main()
{
cin>>sn>>sm>>sx;
for(long long i=0;i<sm;i++)
{
cin>>a[i]>>b[i]>>kk[i];
}

s=1;
t=sn;
nn=t+1;

//这个精度问题还是很坑。。。
long double b=0,d=1000000000.0;
//好坑的东西! 我就操!
while(d-b > 1e-13)//这里精度太小,竟然会死循环。。。
{
long double mid=(b+d)/2;
if( check(mid)==1 )
{
b = mid;
}
else
{
d = mid;
}
}
printf("%.20Lf",b);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: