• 题意
    • n个插座(不重复),m个电器(不重复),k个转接头(将s2转成s1)
    • 每个电器只能插在对应型号的插座上,但是每种类型的转接头无限且可以无限叠加
  • 题解
    • 其实最大流问题在于如何通过题目得出是否拆点以及如何限制流量(一般问什么,就限制什么)
    • 这题种不需要拆点,因为转接头是无限的,即插头之间的转换次数是无限制的,不存在步数限制拆分或者功能拆分问题,所以在可转接的插座之间直接连边,流量无限
    • 转化一下,这题要求的就是最多能接几台电器,那么限制关系就要从电器入手,直接将插座点连接到电器点,流量限制为1,实际上,这一层只是为了方便理解,电器只有单一的接受功能,不存在改变后的输出功能,所以可以直接将电器对应的插座连到汇点
    • 最后将源点接到初始的插座,流量为1
    • 将电器(对应的插座)接入汇点,流量为1
    • 实际上,除了关键点的流量限制以外,其他的流量都可以设置为inf,避免错误出现
  • 代码
    • #include<cstdio>
      #include<cstring>
      #include<algorithm>
      #include<queue>
      #include<iostream>
      #include<map>
      #include<string>
      using namespace std;
      #define rep(i,a,n) for(int i=a;i<=n;++i)
      #define per(i,a,n) for(int i=n;i>=a;--i)
      typedef long long ll;
      typedef unsigned long long ull;
      const int inf=1<<29,N=10010,M=300010;
      int head[N],ver[N],edge[N],Next[N],d[N];
      int n,m,k,s,t,tot,maxflow;
      queue<int>q;
      void add(int x,int y,int z) {
          ver[++tot]=y;
          edge[tot]=z;
          Next[tot]=head[x];
          head[x]=tot;
          ver[++tot]=x;
          edge[tot]=0;
          Next[tot]=head[y];
          head[y]=tot;
      }
      bool bfs() { //在残量网络上构造分层图
          memset(d,0,sizeof(d));
          while(q.size())q.pop();
          q.push(s);
          d[s]=1;
          while(q.size()) {
              int x=q.front();
              q.pop();
              for(int i=head[x]; i; i=Next[i])
                  if(edge[i]&&!d[ver[i]]) {
                      q.push(ver[i]);
                      d[ver[i]]=d[x]+1;
                      if(ver[i]==t)return 1;
                  }
          }
          return 0;
      }
      int dinic(int x,int flow) { //在当前分层图上增广
          if(x==t)return flow;
          int rest=flow,k;
          for(int i=head[x]; i; i=Next[i])
              if(edge[i]&&d[ver[i]]==d[x]+1) {
                  k=dinic(ver[i],min(rest,edge[i]));
                  if(!k)d[ver[i]]=0;
                  edge[i]-=k;
                  edge[i^1]+=k;
                  rest-=k;
              }
          return flow-rest;
      }
      string str1,str2;
      map<string,int>mp;
      int cnt;
      int main() {
          while(scanf("%d", &n)!=EOF) {
              cnt=1;
              mp.clear();
      		tot=1;
              memset(head,0,sizeof(head));
              s=0,t=1;
              rep(i,1,n){
              	cin>>str1;
              	if(!mp[str1])mp[str1]=++cnt;
              	add(s,mp[str1],1);
      		}
      		scanf("%d", &m);
      		rep(i,1,m){
      			cin>>str1>>str2;
      //			mp[str1]=++cnt;
      			if(!mp[str2]){
      				mp[str2]=++cnt;
      			}
      			add(mp[str2],t,1);
      			//add(mp[str1],t,1);
      			//add(mp[str2],mp[str1],1);
      		}
      		scanf("%d", &k);
      		rep(i,1,k){
      			cin>>str1>>str2;
      			if(!mp[str1])mp[str1]=++cnt;
      			if(!mp[str2])mp[str2]=++cnt;
      			//这里必须是inf而不是1,因为某个插头可能可以由其他许多插头转接而来,这样以来,流量就不仅仅为1了 
      			add(mp[str2],mp[str1],inf);
      		}
      		maxflow=0;
      		int flow=0;
      		while(bfs())
      			while(flow=dinic(s,inf))maxflow+=flow;
      		cout<<m-maxflow<<endl;
          }
          return 0;
      }

发表评论

邮箱地址不会被公开。 必填项已用*标注