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 }
View Code

方法二:考虑两头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 }
View Code

总觉得网络流和贪心有妙不可言的关系,因为不是第一次见到网络流模型转成贪心问题了。

posted @ 2017-07-11 17:25  Blue233333  阅读(173)  评论(0编辑  收藏  举报