题解 P2887 【[USACO07NOV]防晒霜Sunscreen】
这题我选择使用网络流。做题之前没看题解感觉很像网络流,就试着做了一下,主要是内存原因限制了这题的解法。 1.通过原点向防晒霜建边,边权为cover 2.防晒霜向适合的奶牛建边,复杂度为n²,边权为1 3.奶牛向汇点建边,边权为1, 跑一遍dinic就可以了,实现的时候可以通过开小数组来ac(128mb作者按照建边的规模开貌似会mle)
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=5005;
int spf[maxn],cover[maxn],C,L,c[maxn],l[maxn],r[maxn];
inline void init(){
scanf("%d%d",&C,&L);
for (int i=1;i<=C;i++){
scanf("%d%d",&l[i],&r[i]);
}
for (int i=1;i<=L;i++){
scanf("%d%d",&spf[i],&cover[i]);
}
}
const int maxm=2000000;
struct edge{
int link,next,val,opp;
}e[maxm];
int tot,S,T,head[maxn];
inline int get(int x){
return x+L;
}
inline void add(int u,int v,int w){
e[++tot]=(edge){v,head[u],w,0}; head[u]=tot;
}
inline void insert(int u,int v,int w){
add(u,v,w); e[tot].opp=tot+1; add(v,u,0); e[tot].opp=tot-1;
}
inline void build(){
S=0;
for (int i=1;i<=L;i++){
for (int j=1;j<=C;j++){
if (spf[i]>=l[j]&&spf[i]<=r[j]){
insert(i,get(j),1);
}
}
insert(S,i,cover[i]);
}
T=C+L+1;
for (int i=1;i<=C;i++){
insert(get(i),T,1);
}
}
int h,t,q[maxn],dis[maxn];
inline bool bfs(){
memset(dis,-1,sizeof(dis));
h=0; t=1; dis[S]=0; q[1]=S;
while (h<t){
int u=q[++h];
for (int i=head[u];i;i=e[i].next){
int v=e[i].link;
if (dis[v]==-1&&e[i].val){
dis[v]=dis[u]+1;
q[++t]=v;
if (v==T) return 1;
}
}
}
return 0;
}
const int inf=1e9;
int cur[maxn],ans;
inline void clean(){
memcpy(cur,head,sizeof(cur));
}
inline void backflow(int i,int w){
e[i].val-=w;
e[e[i].opp].val+=w;
}
int dinic(int u,int flow){
if (!flow||u==T) return flow;
int used=0;
for (int i=cur[u];i;i=e[i].next){
int w,v=e[i].link;
if (dis[u]+1==dis[v]&&e[i].val){
w=dinic(v,min(flow-used,e[i].val));
used+=w;
backflow(i,w);
if (w) cur[u]=i;
if (used==flow) return flow;
}
}
if (!used) dis[u]=-1;
return used;
}
inline void solve(){
build();
while (bfs()){
clean();
ans+=dinic(S,inf);
}
printf("%d\n",ans);
}
int main(){
init();
solve();
return 0;
}