bzoj 4819: [Sdoi2017]新生舞会

题目链接

bzoj4819: [Sdoi2017]新生舞会

题解

很裸的01分规,化完式子大概是这样的
$ \sum ai - \sum bi *C$
二分最大比值C建图,
当最大费用 >=0 时,二分下界调大
否则上界调小
在洛谷似乎有些卡常,但借助bzoj的总时限还是跑过去了

然而开始的时候我是用$ \sum bi *C-\sum ai $这个式子做的
然后GG...调不动了.....重打

代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define eps 1e-7
using std::queue;
inline int read() {
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
    while (c<='9'&&c>='0') x=x*10+c-'0',c=getchar();
    return x*f;
}
const int maxn = 307;
int n;
double a[maxn][maxn];
double b[maxn][maxn];
struct node{
    int flow,u,v,next;double cost;
}edge[maxn*maxn*3];
int num=1,head[maxn<<1],S,T,tmp;
inline void add_edge(int u,int v,int flow,double cost) {
    edge[++num].u = u;edge[num].v = v;edge[num].flow = flow;edge[num].cost = cost,edge[num].next = head[u];head[u] = num;
}
inline void ADD(int u,int v,int flow,double cost) { add_edge(u,v,flow,cost); add_edge(v,u,0,-cost); }
void rebuild(double C) {
    num=1;
    memset(head,0,sizeof head);
    for (int i = 1;i <= n;++i) 
        ADD(S,i,1,0), ADD(n + i,T,1,0);
    for (int i = 1;i <= n;++ i)  for (int j = 1;j <= n;++ j) 
            ADD(i,n + j,1, a[i][j]-b[i][j]*C);
}

double dis[maxn<<2];int pre[maxn<<2];bool vis[maxn<<2]; 
bool spfa() {
    queue<int>q;
    for(int i=S;i<=T;++i) dis[i]=-0x3f3f3f3f,pre[i]=0;
    memset(vis,0,sizeof vis);
    q.push(S);vis[S] = true;dis[S] = 0;
    while (!q.empty()) {
        int u = q.front();q.pop();
        for (int v,i = head[u];i;i = edge[i].next) {
            v = edge[i].v;
            if (edge[i].flow > 0&&dis[v] < dis[u] + edge[i].cost) {
                pre[v] = i;
                dis[v] = dis[u] + edge[i].cost;
                if (!vis[v]) q.push(v),vis[v] = 1;
            }
        }
        vis[u] = 0;
    }
    return dis[T] != -0x3f3f3f3f;
}

double calc() {
    double ret = 0;int MF = 0x3f3f3f3f;
    for (int i = T;i != S;i = edge[pre[i]].u) 
        MF = std::min(edge[pre[i]].flow,MF);
    for (int i = T;i != S;i = edge[pre[i]].u) {
        edge[pre[i]].flow -= MF;
        edge[pre[i]^1].flow += MF;
        ret += edge[pre[i]].cost * 1.0*MF;
    }
    return ret;
}

double mfmc() {
    double ret=0;
    while(spfa()) 
    ret += calc();
    return ret;
}

bool check() { return mfmc()>=0 ? true : false ;   }

int main() {
    n = read();
    S = 0,T = n*2+1;
    for (int i = 1;i <= n;++ i)  for (int j = 1;j <= n;++ j) 
            a[i][j]=read();
    for (int i = 1;i <= n;++ i)  for (int j = 1;j <= n;++ j) 
            b[i][j] = read();
    //printf("%lf %lf\n",dis[0],0x3f3f3f3f);
    double l=0,r=1000009.0;
    while(r - l > eps) {
        double mid = (l + r) / 2;
        rebuild(mid);
        if(check()) l=mid;
        else r=mid;
    }
    printf("%lf\n",l);
    return 0;
}

posted @ 2018-03-27 19:20  zzzzx  阅读(130)  评论(0编辑  收藏  举报