POJ1087 ZOJ1157(最大流Isap+map映射)

题意:在一个会议室里有n种插座,每种插座一个;每个插座只能插一种以及一个电器(或者适配器);
      有m个电器,每个电器有一个插头需要插在相应一种插座上;不是所有电器都能在会议室找到相应插座;
      有k种适配器,每种适配器可以有无限多数量;每种适配器(a, b)可以把b类插座变为a类插座;
      问最后有多少个电器无法使用。

建图:

(1) 源点到每种插座连一条权值为1的边

(2) 每个电器到汇点连一条权值为1的边

(3) m个电器中,连一条对应插座到该个电器的边,权值为1

(4)k种适配器,连一条B到A的边,权值为inf

题目意思最多也就300个点,怎么开n=300,就re了,开600多,就AC了,求过路大神指点

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <map>
  7 using namespace std;
  8 #define inf 0x7fffffff
  9 #define N 666
 10 #define M 350000
 11 map<string,int> mp;
 12 struct Edge
 13 {
 14     int v,w,next;
 15     Edge(){}
 16     Edge(int V,int W,int NEXT):v(V),w(W),next(NEXT){}
 17 }edge[M];
 18 int pre[N],cur[N],dis[N],gap[N];
 19 int size,head[N];
 20 int a[105];
 21 void Init()
 22 {
 23     memset(head,-1,sizeof(head));
 24     size = 0;
 25 }
 26 void InsertEdge(int u,int v,int w)// 加边 
 27 {
 28     edge[size] = Edge(v,w,head[u]);
 29     head[u] = size++;
 30     edge[size] = Edge(u,0,head[v]);
 31     head[v] = size++;
 32 }
 33 int Isap(int st,int ed,int n) // Isap模板 
 34 {
 35     for(int i=0; i<=n; i++)
 36     {
 37         gap[i] = dis[i] = 0;
 38         cur[i] = head[i];
 39     }
 40     int u = pre[st] = st;
 41     int aug = inf ,maxflow = 0;
 42     while(dis[st] < n)
 43     {
 44 loop:
 45         for(int &i=cur[u]; i!=-1; i=edge[i].next)
 46         {
 47             int v = edge[i].v;
 48             if(edge[i].w && dis[u]==dis[v]+1)
 49             {
 50                 aug = min(aug,edge[i].w);
 51                 pre[v] = u;
 52                 u = v;
 53                 if(v==ed)
 54                 {
 55                     maxflow += aug;
 56                     for(u=pre[u]; v!=st; v=u,u=pre[u])
 57                     {
 58                         edge[cur[u]].w -= aug;
 59                         edge[cur[u]^1].w += aug;
 60                     }
 61                     aug = inf;
 62                 }
 63                 goto loop;
 64             }
 65         }
 66         int mindis = n;
 67         for(int i=head[u]; i!=-1; i=edge[i].next)
 68         {
 69             int v = edge[i].v;
 70             if(edge[i].w && dis[v] < mindis)
 71             {
 72                 cur[u] = i;
 73                 mindis = dis[v];

 74             }
 75         }
 76         if(--gap[dis[u]]==0) break;
 77         gap[dis[u]=mindis+1]++;
 78         u = pre[u];
 79     }
 80     return maxflow;
 81 }
 82 
 83 int main()
 84 {
 85     int T,n,m,k,st,ed,nv;
 86     string s1,s2;
 87     Init();
 88     mp.clear();
 89     scanf("%d",&n);
 90     st = 0 ; nv = 1; //源点st为0,nv初始化为1,方便源点从0开始 
 91     for(int i=0; i<n; i++)
 92     {
 93         cin>>s1;
 94         if(mp.find(s1)==mp.end()) mp[s1] = nv++; //map映射 
 95         InsertEdge(st,mp[s1],1); //源点到每种插座连一条权值为1的边
 96     }
 97     scanf("%d",&m);
 98     int cnt=0;
 99     for(int i=0; i<m; i++)
100     {
101         cin>>s1>>s2;
102         if(mp.find(s1)==mp.end()) mp[s1] = nv++; //map映射 
103         if(mp.find(s2)==mp.end()) mp[s2] = nv++; //map映射 
104         InsertEdge(mp[s2],mp[s1],1); //m个电器中,连一条对应插座到该个电器的边,权值为1
105         a[cnt++] = mp[s1]; //数组a记录设备的结点号 
106     }
107     scanf("%d",&k);
108     for(int i=0; i<k; i++)
109     {
110         cin>>s1>>s2;
111         if(mp.find(s1)==mp.end()) mp[s1] = nv++; //map映射 
112         if(mp.find(s2)==mp.end()) mp[s2] = nv++; //map映射 
113         InsertEdge(mp[s2],mp[s1],inf); //k种适配器,连一条B到A的边,权值为inf
114     }
115     ed = nv;// 汇点 
116     for(int i=0; i<cnt; i++)
117     InsertEdge(a[i],ed,1); //每个电器到汇点连一条权值为1的边
118     nv++;
119     printf("%d\n",m-Isap(st,ed,nv)); //输出的答案是设备数减去最大流 
120     return 0;
121 }
View Code

 

 

 

转载于:https://www.cnblogs.com/ar940507/p/3265554.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值