[SDOI2017]新生舞会

题目描述

学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴。

个男生和个女生参加舞会买一个男生和一个女生一起跳舞,互为舞伴。

Cathy收集了这些同学之间的关系,比如两个人之前认识没计算得出 

Cathy还需要考虑两个人一起跳舞是否方便,比如身高体重差别会不会太大,计算得出 ,表示第i个男生和第j个女生一起跳舞时的不协调程度。

当然,还需要考虑很多其他问题。

Cathy想先用一个程序通过求出一种方案,再手动对方案进行微调。

Cathy找到你,希望你帮她写那个程序。

一个方案中有n对舞伴,假设没对舞伴的喜悦程度分别是,假设每对舞伴的不协调程度分别是。令

Cathy希望C值最大。

输入输出格式

输入格式:

第一行一个整数n。

接下来n行,每行n个整数,第i行第j个数表示

接下来n行,每行n个整数,第i行第j个数表示

 

输出格式:

一行一个数,表示C的最大值。四舍五入保留6位小数,选手输出的小数需要与标准输出相等。

 

输入输出样例

输入样例#1:
3
19 17 16
25 24 23
35 36 31
9 5 6
3 4 2
7 8 9
输出样例#1:
5.357143

说明

对于10%的数据,

对于40%的数据,

另有20%的数据,

对于100%的数据,

思路:二分答案+费用流

一开始,边的费用没有想到,其实移一下项就好了。

然后,就见识到了什么叫卡常数,蒟蒻常数巨大。。。

于是就开始借鉴大佬的优化,发现大佬写的是紫书上的板子,果然,手模代码不靠谱吗?

丧失OI路的信心。

事实证明:结构体是极慢的。

 7.3s->4.1s

代码实现:

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define inf -1e9
 5 using namespace std;
 6 const int maxn=110;
 7 const int maxm=maxn*maxn<<2;
 8 queue<int>q;
 9 int n,s,t,a,b;
10 double l,r,mid,ans,error=1e-7;
11 int map[maxn][maxn][2],h[maxn*maxn<<1],hs=1;
12 int e_q[maxm],e_z[maxm],e_n[maxm],p[maxn<<1];
13 bool e_w[maxm],v[maxn<<1];
14 double e_f[maxm],w[maxn<<1];
15 char r_w[30],r_l;
16 int read(int &x){
17     while(r_w[0]=getchar(),r_w[0]<'0'||r_w[0]>'9');r_l=1;
18     while(r_w[r_l]=getchar(),r_w[r_l]>='0'&&r_w[r_l]<='9') r_l++;
19     for(int i=0;i<r_l;i++) x=x*10+r_w[i]-'0';
20 }
21 inline int min_(int x,int y){return x<y?x:y;}
22 void add(int x,int y,double z){
23     ++hs,e_q[hs]=x,e_z[hs]=y,e_n[hs]=h[x],e_w[hs]=true,e_f[hs]=z,h[x]=hs;
24     ++hs,e_q[hs]=y,e_z[hs]=x,e_n[hs]=h[y],e_w[hs]=false,e_f[hs]=-z,h[y]=hs;
25 }
26 void MCMF(){
27     while(1){
28         for(int i=0;i<=t;i++) w[i]=inf;
29         memset(v,0,sizeof(v));
30         q.push(s),w[s]=false;
31         while(!q.empty()){
32             a=q.front(),q.pop(),v[a]=0;
33             for(int i=h[a];i;i=e_n[i])
34             if(e_w[i]&&w[e_z[i]]<e_f[i]+w[a]){
35                 b=e_z[i],p[b]=i;
36                 w[b]=e_f[i]+w[a];
37                 if(!v[b]) q.push(b),v[b]=true;
38             }
39         }
40         if(w[t]==inf||(ans<0&&w[t]<0)) return;
41         else ans+=w[t];
42         for(int i=t;i!=s;i=e_q[p[i]]) e_w[p[i]]=false,e_w[p[i]^1]=true;
43     }
44 }
45 int main(){
46     read(n);
47     s=0,t=n*2+1;
48     for(int i=1;i<=n;i++)
49     for(int j=1;j<=n;j++)
50     read(map[i][j][0]);
51     for(int i=1;i<=n;i++)
52     for(int j=1;j<=n;j++)
53     read(map[i][j][1]);
54     l=0,r=1e4;
55     while(r-l>error){
56         mid=(l+r)/2,ans=0;
57         memset(h,0,sizeof(h)),hs=1;
58         for(int i=1;i<=n;i++) add(s,i,0),add(i+n,t,0);
59         for(int i=1;i<=n;i++)
60         for(int j=1;j<=n;j++)
61         add(i,j+n,map[i][j][0]-mid*map[i][j][1]);
62         MCMF();
63         if(ans>0) l=mid;
64         else r=mid;
65     }
66     printf("%.6lf",r);
67     return 0;
68 }

傻逼题我都改了这么久,药丸药丸。

转载于:https://www.cnblogs.com/J-william/p/6736129.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值