标签:
题意:有f中食物和D种饮料,每头牛只能享用一种食物和饮料,每个食物跟饮料也只能被一头牛享用。现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料。f,d,n都是一百以内的。
思路:就不说一开始的想法了,是最近学习的最大流的建模里面的新的方法。
之前做过几道题,比如poj2391这道,它是比较一般的左边一些点代表着供应,2391这道题就是每个点的牛的数量,右边一个点集代表了需求并与汇点连接,这道题就是每个点能容纳的牛数,然后拆点联一下套模板就好了。
而现在这道题跟2391这道有点相似,那我们就可以把食物当作供应,经过牛这些点,然后走到代表饮料的需求的点。
我个人认为也可以这么理解吧,每一个食物从源点出来,然后经过饮料进入汇点才能组成一对,然后中间必须经过喜欢它们的牛。
但是有一个问题就是如果单纯的食物-》牛-》饮料,那么就会出现多对食物与饮料被一个牛享用的情况,所以把牛拆了,变成食物->牛->牛->饮料,其中这两个牛是同一个,边的容量都是1,这么的话就会避免,一个牛享用多对的情况了,因为牛->牛的容量是1。
至于模板,dinic与sap都行,速度差不多,有些情况下貌似sap稍快些。
代码:
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<queue> using namespace std; const int maxn=250; struct node{ int u,v,next,c; }; node edge[maxn<<1]; int head[maxn]; int cnt; int dis[maxn]; int n,m; int ans; void init(){ memset(head,-1,sizeof(head)); cnt=0; memset(dis,-1,sizeof(dis)); ans=0; } void add(int a,int b,int c){ edge[cnt].u=a; edge[cnt].v=b; edge[cnt].c=c; edge[cnt].next=head[a]; head[a]=cnt++; } int bfs()// 给各点分层,离源点的远近分 { memset(dis, -1, sizeof(dis)); queue<int> q; dis[1] = 0; q.push(1); int i; int cur; while(!q.empty()) { cur = q.front(); q.pop(); for(i = head[cur]; i != -1; i = edge[i].next) { if(dis[edge[i].v] == -1 && edge[i].c > 0) { dis[edge[i].v] = dis[cur] + 1; q.push(edge[i].v); } } } if(dis[m] < 0) return 0; return 1; } int Find(int x,int low){//找增广 int a; if(x==m) return low; for(int i=head[x];i!=-1;i=edge[i].next){ int v=edge[i].v; if(dis[v]==dis[x]+1 && edge[i].c>0 &&(a=Find(v,min(low,edge[i].c)))) { edge[i].c -=a; edge[i^1].c +=a; return a; } } return 0; } void dinic(){ int temp; while(bfs()){ // printf("%d\n",tmp); // if(tmp==0) break; temp=Find(1,0x3f3f3f3f); ans+=temp; } printf("%d\n",ans); } int main(){ while(~scanf("%d%d",&n,&m)){ int a,b,flow; init(); for(int i=1;i<=n;i++){ scanf("%d%d%d",&a,&b,&flow); add(a,b,flow); add(b,a,0); } dinic(); } return 0; }
版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/hitwhacmer1
标签:
原文地址:http://blog.csdn.net/hitwhacmer1/article/details/47735801