P3705 [SDOI2017]新生舞会 01规划+费用流

P3705 [SDOI2017]新生舞会


思路:
这个方程式一看就是01规划。我们考虑二分之后,怎么搞。


因为所以人都要匹配,跑费用就可以了。

#include<bits/stdc++.h>
#define re register
#define LL long long
using namespace std;

const LL maxn = 200 + 10;
const LL maxm=1e6+10;
const LL inf=1<<30;
const LL INF = 0x3f3f3f3f3f3f3f3f;

struct po {
    LL to;
    double dis;
    LL nxt, w;
} edge[maxm<<1];

struct max_folw {
    double dis[maxn];
    LL vis[maxn];
    LL head[maxn];
    LL n,s,t,cut=-1;
    LL ans=0;
    double fy=0;

    void init(LL N, LL S, LL T) {
        ans=0, fy=0;
        cut=-1;
        n=N, s=S, t=T;
        memset(head, -1, sizeof(head));
    }

    void add_edge(LL from,LL to,LL w,double dis) {
        edge[++cut].nxt=head[from];
        edge[cut].to=to;
        edge[cut].w=w;
        edge[cut].dis=dis;
        head[from]=cut;
    }
    void add(LL from,LL to,LL w,double dis) {
        add_edge(from,to,w,dis);
        add_edge(to,from,0,-dis);
    }
    bool spfa() {
        memset(vis,0,sizeof(vis));
        for(re LL i=0; i<=n; i++)
            dis[i]=inf;
        dis[t]=0;
        vis[t]=1;
        deque<LL> q;
        q.push_back(t);
        while(!q.empty()) {
            LL u=q.front();
            vis[u]=0;
            q.pop_front();
            for(re LL i=head[u]; i!=-1; i=edge[i].nxt) {
                LL v=edge[i].to;
                if(edge[i^1].w>0&&dis[v]>dis[u]-edge[i].dis) {
                    dis[v]=dis[u]-edge[i].dis;
                    if(!vis[v]) {
                        vis[v]=1;
                        if(!q.empty()&&dis[v]<dis[q.front()])
                            q.push_front(v);
                        else
                            q.push_back(v);
                    }
                }
            }
        }
        return dis[s]<inf;
    }
    LL dfs(LL u,LL low) {
        if(u==t) {
            vis[t]=1;
            return low;
        }
        LL diss=0;
        vis[u]=1;
        for(re LL i=head[u]; i!=-1; i=edge[i].nxt) {
            LL v=edge[i].to;
            if(!vis[v]&&edge[i].w!=0&&dis[u]-edge[i].dis==dis[v]) {
                LL check=dfs(v,min(edge[i].w,low));
                if(check>0) {
                    fy+=check*edge[i].dis;
                    edge[i].w-=check;
                    edge[i^1].w+=check;
                    low-=check;
                    diss+=check;
                    if(low==0)
                        break;
                }
            }
        }
        return diss;
    }
    void max_flow() {
        while(spfa()) {  //流量+k
            vis[t]=1;
            while(vis[t]) {
                memset(vis,0,sizeof(vis));
                ans+=dfs(s,inf);
            }
        }
    }
} flow;

LL a[105][105], b[105][105];
int n;
int ok(double r){
    flow.init(2*n+5, 0, 2*n+1);
    for(int i=1; i<=n; i++){
        flow.add(0, i, 1, 0);
        flow.add(i+n, 2*n+1, 1, 0);
        for(int j=1; j<=n; j++){
            flow.add(i, n+j, 1, r*b[i][j]-a[i][j]);
        }
    }
    flow.max_flow();
    return flow.fy>=0;
}

int main(){

    scanf("%d", &n);
    for(LL i=1; i<=n; i++){
        for(LL j=1; j<=n; j++){
            scanf("%lld", &a[i][j]);
        }
    }
    for(LL i=1; i<=n; i++){
        for(LL j=1; j<=n; j++){
            scanf("%lld", &b[i][j]);
        }
    }
    double L=0, R=1<<30, mid;
    int siz=60;
    while(siz--){
        mid=(L+R)/2;
        if(ok(mid)){//<0
            R=mid;
        }
        else{
            L=mid;
        }
    }
    printf("%.6f\n", mid);

    return 0;
}
posted @ 2020-11-17 17:46  liweihang  阅读(93)  评论(0编辑  收藏  举报
Live2D