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
", 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
", i,val[i],i,cur[i]);
addedge(s,i,val[i]);
}
// printf("sss
");
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
");
int ans = Maxflow(s,t);
printf("%d
", ans);
}
return 0;
}