BZOJ1707: [Usaco2007 Nov]tanning分配防晒霜
n头牛,第i头要SPF(某个参数)在Lowi到Highi的药,药m种每种SPF为Vi,数量为Numi,求最多能满足几头牛。
方法一:什么都看不出来,只知道第i头牛能和一些药匹配,于是网络流,牛向药连容量1的边,起点向牛容量1,药向终点容量为药数量,最大流。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstring> 6 //#include<iostream> 7 using namespace std; 8 9 int n,m; 10 #define maxn 5011 11 #define maxm 3000011 12 struct Edge{int from,to,next,cap,flow;}; 13 const int inf=0x3f3f3f3f; 14 struct Network 15 { 16 Edge edge[maxm];int n,le; 17 int first[maxn],cur[maxn],dis[maxn]; 18 void clear(int n) 19 { 20 this->n=n;le=2; 21 memset(first,0,sizeof(first)); 22 } 23 void add_edge(int x,int y,int cap) 24 { 25 Edge &e=edge[le]; 26 e.to=y;e.from=x; 27 e.cap=cap;e.flow=0; 28 e.next=first[x]; 29 first[x]=le++; 30 } 31 void insert(int x,int y,int cap) 32 { 33 add_edge(x,y,cap); 34 add_edge(y,x,0); 35 } 36 int s,t; 37 int que[maxn],head,tail; 38 bool bfs() 39 { 40 memset(dis,0,sizeof(dis)); 41 dis[s]=1; 42 que[head=(tail=1)-1]=s; 43 while (head!=tail) 44 { 45 const int now=que[head++]; 46 for (int i=first[now];i;i=edge[i].next) 47 { 48 const Edge &e=edge[i]; 49 if (e.cap>e.flow && !dis[e.to]) 50 { 51 dis[e.to]=dis[now]+1; 52 que[tail++]=e.to; 53 } 54 } 55 } 56 return dis[t]; 57 } 58 int dfs(int x,int a) 59 { 60 if (x==t || !a) return a; 61 int flow=0,f; 62 for (int &i=cur[x];i;i=edge[i].next) 63 { 64 Edge &e=edge[i]; 65 if (dis[e.to]==dis[x]+1 && (f=dfs(e.to,min(a,e.cap-e.flow)))>0) 66 { 67 e.flow+=f; 68 flow+=f; 69 edge[i^1].flow-=f; 70 a-=f; 71 if (!a) break; 72 } 73 } 74 return flow; 75 } 76 int Dinic(int s,int t) 77 { 78 this->s=s;this->t=t; 79 int ans=0; 80 while (bfs()) 81 { 82 for (int i=1;i<=n;i++) cur[i]=first[i]; 83 ans+=dfs(s,inf); 84 } 85 return ans; 86 } 87 }G; 88 struct Point{int low,high;}a[maxn]; 89 int x; 90 int main() 91 { 92 scanf("%d%d",&n,&m); 93 G.clear(n+m+2); 94 int s=n+m+1,t=s+1; 95 for (int i=1;i<=n;i++) G.insert(s,i,1); 96 for (int i=1;i<=n;i++) scanf("%d%d",&a[i].low,&a[i].high); 97 for (int i=1;i<=m;i++) 98 { 99 scanf("%d",&x); 100 for (int j=1;j<=n;j++) 101 if (a[j].low<=x && a[j].high>=x) 102 G.insert(j,i+n,1); 103 scanf("%d",&x); 104 G.insert(i+n,t,x); 105 } 106 printf("%d\n",G.Dinic(s,t)); 107 return 0; 108 }
方法二:考虑两头High不同的牛,High小的能选的药一定不会超过High大的的上界。分类讨论一下Low的情况,可以发现,按High排序后,为了使对后面的影响最小,High小的那些牛应尽量选择spf小的药,因为这些后面的牛不一定选得到;而如果选了某个药导致后面某头牛不能吃药,那对答案是没有影响的,因为他们两头牛选药起冲突了,给谁吃都一样嘛。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstring> 6 //#include<iostream> 7 using namespace std; 8 9 int n,m; 10 #define maxn 2511 11 struct Point 12 { 13 int low,high; 14 bool operator < (const Point &a) const {return high<a.high;} 15 }a[maxn]; 16 struct Bottle 17 { 18 int num,v; 19 bool operator < (const Bottle &a) const {return v<a.v;} 20 }b[maxn]; 21 int find(int x) 22 { 23 int L=1,R=m; 24 while (L<R) 25 { 26 int mid=(L+R)>>1; 27 if (b[mid].v<x) L=mid+1; 28 else R=mid; 29 } 30 return L; 31 } 32 int main() 33 { 34 scanf("%d%d",&n,&m); 35 for (int i=1;i<=n;i++) scanf("%d%d",&a[i].low,&a[i].high); 36 for (int i=1;i<=m;i++) scanf("%d%d",&b[i].v,&b[i].num); 37 sort(a+1,a+1+n); 38 sort(b+1,b+1+m); 39 int ans=0; 40 for (int i=1;i<=n;i++) 41 { 42 int p=find(a[i].low); 43 while (p<=m && b[p].v<=a[i].high && !b[p].num) p++; 44 if (p<=m && b[p].v<=a[i].high) b[p].num--,ans++; 45 } 46 printf("%d\n",ans); 47 return 0; 48 }
总觉得网络流和贪心有妙不可言的关系,因为不是第一次见到网络流模型转成贪心问题了。