题意:给你n个区间,给你m个数值,每个数值有m_num个。如果一个数值在一个区间里面那么这个区间就可以被占领,问你最多可以占领多少个区间。
思路:乍一眼就是多重匹配,找到每个点和可以匹配的区间有关系就好了。但是就怕超时,但是我用DINIC就过了。
网络流解决多重匹配的问题:简单。首先虚拟sink,source。
source到每一个点连接一条边权为此点可以被匹配的次数,然后向它可以匹配的点(这道题是区间,大同小异)连接一条权值为1的边,表示这一次这个点我要不要它,然后匹配点向sink连一条权值为权值>=1的边,因为主要的限流在前面就被处理过了,这里不影响结果就好了。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define inf 0x7fffffff using namespace std; const int N=2500+10; int C,L,st,ed; struct node { int low,up; }cow[N]; struct nnode { int spf,num; }sun[N]; struct nodee { int v,next,flow; }e[N*N*2]; int head[N*2],cnt; void Init() { memset(head,-1,sizeof(head)); cnt=0; } void add(int a,int b,int c) { e[cnt].v=b; e[cnt].flow=c; e[cnt].next=head[a]; head[a]=cnt++; e[cnt].v=a; e[cnt].flow=0; e[cnt].next=head[b]; head[b]=cnt++; } class Dinic { public: int spath() { queue<int>q; while(!q.empty()) q.pop(); memset(dis,-1,sizeof(dis)); dis[st]=0; q.push(st); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i+1;i=e[i].next) { int v=e[i].v; if(dis[v]==-1&&e[i].flow>0) { dis[v]=dis[u]+1; q.push(v); } } } return dis[ed]!=-1; } int Min(int a,int b) { if(a<b) return a; return b; } int dfs(int u,int flow) { int cost=0; if(u==ed) return flow; for(int i=head[u];i+1;i=e[i].next) { int v=e[i].v; if(dis[v]==dis[u]+1&&e[i].flow>0) { int min=dfs(v,Min(e[i].flow,flow-cost)); if(min>0) { e[i].flow-=min; e[i^1].flow+=min; cost+=min; if(cost==flow) break; } else dis[v]=-1; } } return cost; } int result() { int res=0; while(spath()) { res+=dfs(st,inf); } return res; } private: int dis[N*2]; }dinic; void Input() { for(int i=1;i<=C;i++) { scanf("%d%d",&cow[i].low,&cow[i].up); } for(int i=1;i<=L;i++) { scanf("%d%d",&sun[i].spf,&sun[i].num); } } void treatment() { st=0;ed=C+L+1; for(int i=1;i<=L;i++) { add(st,i,sun[i].num); for(int j=1;j<=C;j++) { if(sun[i].spf>=cow[j].low&&sun[i].spf<=cow[j].up) add(i,j+L,1); } } for(int i=1;i<=C;i++) add(i+L,ed,1); printf("%d\n",dinic.result()); } int main() { while(~scanf("%d%d",&C,&L)) { Init(); Input(); treatment(); } return 0; }