sgu 242 Student's Morning--最大流 或 多重匹配

来源:互联网 发布:阿里云待遇 编辑:程序博客网 时间:2024/05/01 21:57
/*n同学分别来自不同的学校,他们想去学校玩,但是不像一个人去,所以去某个学校的人数应>=2问是否有k个学校满足要求建边:[s,学校] 权为2[学校,同学] 权为1[同学,t] 权为1据说这题可以用匹配做,以后看看*/#include<stdio.h>#include<string.h>#define inf 0x7ffffffstruct edge{int u,v,f,next;}e[100010];int head[410],yong;int n,k,s,t;void ini(){memset(head,-1,sizeof(head));yong=0;s=0,t=2*n+1;}void adde(int from,int to,int flow){e[yong].u=from,e[yong].v=to,e[yong].f=flow;e[yong].next=head[from],head[from]=yong++;e[yong].u=to,e[yong].v=from,e[yong].f=0;e[yong].next=head[to],head[to]=yong++;}int d[410],num[410];  int min(int a,int b){return a<b?a:b;}      int sap_gap(int u,int f,int s,int t){          if(u==t)              return f;          int i,v,mind=t,last=f,cost;          for(i=head[u];i!=-1;i=e[i].next)          {              v=e[i].v;              int flow=e[i].f;              if(flow>0)        {                  if(d[u]==d[v]+1)                  {                      cost=sap_gap(v,min(last,flow),s,t);                      e[i].f-=cost;                      e[i^1].f+=cost;                      last-=cost;                            if(d[s]>=t+1)                          return f-last;                            if(last==0)                          break;                  }                  if(d[v]<mind)                      mind=d[v];              }          }                if(last==f)          {              --num[d[u]];              if(num[d[u]]==0)                  d[s]=t+1;              d[u]=mind+1;              ++num[d[u]];          }          return f-last;      }      int max_f(int s,int t)    {        int f=0;          memset(d,0,sizeof(d));          memset(num,0,sizeof(num));          for(num[s]=t+1;d[s]<t+1;)              f+=sap_gap(s,inf,s,t);          return f;     }  int main(){int i,nn,j,a;while(scanf("%d%d",&n,&k)!=EOF){ini();for(i=1;i<=n;++i){scanf("%d",&nn);while(nn--){scanf("%d",&a);adde(a,n+i,1);}}for(i=1;i<=n;i++)adde(s,i,2);for(i=n+1;i<=n+n;i++)adde(i,t,1);j=max_f(s,t);if(j<k*2)printf("NO\n");else{printf("YES\n");i=1;while(k--){printf("2 ");j=head[i];while(e[j].f!=0) j=e[j].next;printf("%d ",e[j].v-n);j=e[j].next;while(e[j].f!=0) j=e[j].next;printf("%d\n",e[j].v-n);i++;}}}return 0;}


写了两种多重匹配:1.拆点2.用结构体表示多重匹配点

前者适用于所有点的多重匹配数量相同

后者没什么限制

/*用多重匹配写的把每个学校拆成两个点 然后匹配*/#include<iostream>using namespace std;int n,k;int map[210][410];int match[410],vis[410];int dfs(int i){int j;for(j=0;j<k*2;++j){if(!vis[j]&&map[i][j])//忘了写后面这个条件{vis[j]=1;if(match[j]==-1||dfs(match[j])){match[j]=i;return 1;}}}return 0;}int main(){int i,nn,j,a;while(cin>>n>>k){memset(map,0,sizeof(map));for(i=0;i<n;++i){cin>>nn;while(nn--){cin>>a;map[i][(a-1)*2]=1;map[i][(a-1)*2+1]=1;}}a=0;memset(match,-1,sizeof(match));for(i=0;i<n;++i){memset(vis,0,sizeof(vis));if(dfs(i))a++;}if(a==2*k){cout<<"YES"<<endl;for(i=0;k;){if(match[i]!=-1&&match[i+1]!=-1){cout<<"2 "<<(match[i]+1)<<" "<<(match[i+1]+1)<<endl;k--;}i=i+2;}}else cout<<"NO"<<endl;}return 0;}



/*用多重匹配写的每个学校是一个结构体,里边保存匹配信息对应普通匹配的  if(match[j]==-1||dfs(match[j]))多重匹配则是    if(匹配还未用完) 匹配成功     相当于match[j]==-1else 尝试替换某个匹配         相当于dfs(match[j])*/#include<iostream>#include<vector>using namespace std;int n,k;int map[210][210],vis[210];struct node{int n;vector<int>match;}school[210];int dfs(int i){int j,k;for(j=0;j<n;++j){if(!vis[j]&&map[i][j]){vis[j]=1;if(school[j].n>0){--school[j].n;school[j].match.push_back(i);return 1;}for(k=0;k<school[j].match.size();++k){if(dfs(school[j].match[k])){school[j].match[k]=i;return 1;}}}}return 0;}int main(){int i,nn,j,a;while(cin>>n>>k){for(i=0;i<n;++i){school[i].n=2;school[i].match.clear();}memset(map,0,sizeof(map));for(i=0;i<n;++i){cin>>nn;while(nn--){cin>>a;map[i][a-1]=1;}}a=0;for(i=0;i<n;++i){memset(vis,0,sizeof(vis));if(dfs(i))a++;}if(a==2*k){cout<<"YES"<<endl;for(i=0;k;){if(school[i].n==0){cout<<"2 "<<(school[i].match[0]+1)<<" "<<(school[i].match[1]+1)<<endl;k--;}++i;}}else cout<<"NO"<<endl;}return 0;}



原创粉丝点击