D - Seat Assignment ZOJ - 3997 网络流

D - Seat Assignment ZOJ - 3997 网络流

题目大意:

电影院一共有m个位置,\(A_i\) 表示有 \(A_i\) 个人想做位置是 \(i\) 的倍数的位置,问最多可以让多少个人坐到他们想做的位置上?

题解:

\(lcm(1,2,...,10)=2520\) ,所以每一个周期是2520,那么对一个周期进行讨论,打个表发现只有48种本质不同的数,这个本质不同表示的是只有48种数在1~10内有不同的约数。可以给每种数打个标记存下来。

建图,对于1~10的每一个数建一条边到源点,建边到这48种本质不同的是 i 的倍数的数,容量都是 \(A_i\) ,最后就是这48种数建边到汇点,容量是在m中这个数的个数。

重点应该在求这个48种数到汇点的容量,这个首先预处理可以求出一个周期每一个数是属于48种数中的哪一种,然后求出每一个数在m中的数量即可。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 3000;
struct edge{
    int u,v,c,f;
    edge(int u=0,int v=0,int c=0,int f=0):u(u),v(v),c(c),f(f){}
};
vector<edge>e;
vector<int>G[maxn];
int level[maxn],iter[maxn],m;
void init(int num){
    e.clear();
    for(int i=0;i<=num;i++) G[i].clear();
}
void addedge(int u,int v,int c){
    e.push_back(edge(u,v,c,0));
    e.push_back(edge(v,u,0,0));
    m = e.size();
    G[u].push_back(m-2);
    G[v].push_back(m-1);
}
queue<int>q;
void BFS(int s,int num){
    for(int i=0;i<=num+10;i++) level[i] = -1;
    while(!q.empty()) q.pop();
    level[s] = 0,q.push(s);
    while(!q.empty()){
        int u = q.front();q.pop();
        for(int v=0;v<G[u].size();v++){
            edge& now = e[G[u][v]];
            if(now.c>now.f&&level[now.v]<0){
                level[now.v] = level[u] + 1;
                q.push(now.v);
            }
        }
    }
}
int dfs(int u,int t,int f){
    if(u == t) return f;
    for(int &v=iter[u];v<G[u].size();v++){
        edge &now = e[G[u][v]];
        if(now.c>now.f&&level[u]<level[now.v]){
            int d = dfs(now.v,t,min(f,now.c-now.f));
            if(d>0){
                now.f += d;
                e[G[u][v]^1].f -= d;
                return d;
            }
        }
    }
    return 0;
}
int Maxflow(int s,int t){
    int flow = 0;
    while(true){
        BFS(s,t);
        if(level[t]<0) return flow;
        for(int i=0;i<=t;i++) iter[i] = 0;
        int f = 0;
        while((f=dfs(s,t,inf))>0) flow+=f;
        // printf("flow = %d\n", flow);
    }
    return flow;
}

int num[maxn],vis[maxn],lcm,cnt,cur[maxn];
void Init(){
    lcm = 2520,cnt = 0;
    for(int i=0;i<lcm;i++){
        int S = 0;
        for(int j=1;j<=10;j++){
            if(i%j==0) S|=(1<<j);
        }
        if(!vis[S]){
            vis[S] = ++cnt;
            cur[cnt] = S;
        }
        num[i] = vis[S];
    }
}
int val[maxn];
int main(){
    Init();
    int t;
    scanf("%d",&t);
    while(t--){
        init(70);
        int M;
        scanf("%d",&M);
        for(int i=0;i<=cnt;i++) val[i] = 0;
        for(int i=0;i<lcm;i++){
            int now = M/lcm;
            if(i&&i<=M%lcm) now++;
            val[num[i]]+=now;
        }
        int s = 0,t = 66;
        for(int i=1;i<=cnt;i++) {
            if(!val[i]) continue;
            // printf("val[%d]=%d cur[%d]=%d\n", i,val[i],i,cur[i]);
            addedge(s,i,val[i]);
        }
        // printf("sss\n");
        for(int i=1;i<=10;i++){
            int x;
            scanf("%d",&x);
            if(!x) continue;
            addedge(i+cnt,t,x);
            for(int j=1;j<=cnt;j++){
                if(!val[j]) continue;
                if(cur[j]&(1<<i)) {
                    addedge(j,cnt+i,x);
                }
            }
        }
        // printf("zz\n");
        int ans = Maxflow(s,t);
        printf("%d\n", ans);
    }
    return 0;
}
posted @ 2020-10-15 09:47  EchoZQN  阅读(86)  评论(0编辑  收藏  举报