UVA 753 --- 二分图匹配
题意:给出一些插头,电器,以及转换器,求不能够匹配的电器的最小的数目;转换器是无限多的,有可能有重边。
分析:典型的二分图匹配,但是看题解也有用最大流做的(最大流并不会建模型)。电器,插头两个集合匹配,无法与电器直接相连的插头需要转换器进行转换。
1 #include<cstdio>
2 #include <string>
3 #include <cstring>
4 #include <iostream>
5 using namespace std;
6 #define repu(i,a,b) for(int i=a;i<b;i++)
7 #define MAXN 240
8 string S;
9 bool visit[MAXN]; ///记录V2中的某个点是否被搜索过
10 int match[MAXN]; ///记录与V2中的点匹配的点的编号
11 int head[MAXN],vis[MAXN],n,m,K;
12 struct edge
13 {
14 int to,next;
15 } e[10020];
16 int number;
17 struct DIAN
18 {
19 string s2;
20 } d[MAXN];
21 struct TRAN
22 {
23 string s1, s2;
24 } zh[MAXN];
25 struct CH
26 {
27 string s;
28 } ch[MAXN];
29 void addedge(int u,int v)
30 {
31 ///向图中加边的算法,注意加上的是有向边
32 ///u为v的后续节点既是v---->u
33 e[number].to=v;
34 e[number].next=head[u];
35 head[u]=number;
36 number++;
37 }
38
39 int Dfs(int j , int k) ///j插座能否通过k转换器得到
40 {
41 if(zh[k].s2 == ch[j].s)
42 return 1;
43 vis[k]=1;
44 repu(i,1,K+1)
45 if(!vis[i])
46 if(zh[k].s2 == zh[i].s1)
47 {
48 if(Dfs(j,i))
49 return 1;
50 vis[i]=0;
51 }
52 return 0;
53
54 }
55 int Find(int i , int j)
56 {
57 memset(vis,0,sizeof(vis));
58 for(int k=1; k<=K; k++)
59 if(d[i].s2 == zh[k].s1)
60 {
61 if(Dfs(j,k))
62 return 1;
63 vis[k]=0;
64 }
65 return 0;
66 }
67 void init()
68 {
69 memset(head,-1,sizeof(head));
70 number = 0;
71 scanf("%d",&n);
72 for(int i=1; i<=n; i++)
73 cin>>ch[i].s;
74 scanf("%d",&m);
75 for(int i=1; i<=m; i++)
76 cin>>S>>d[i].s2;
77 scanf("%d",&K);
78 for(int i=1; i<=K; i++)
79 cin>>zh[i].s1>>zh[i].s2;
80 repu(i,1,m+1) ///电器
81 repu(j,1,n+1) ///插座
82 {
83 if(d[i].s2 == ch[j].s) ///可以直接相连
84 addedge(i,j+m);
85 else if(Find(i,j)) ///如果通过转换器能连接上
86 addedge(i,j+m);///cout<<i<<"-"<<j+m<<endl;
87 }
88 }
89 /// 匈牙利(邻接表)算法
90 bool dfs(int u)
91 {
92 int v;
93 for(int i = head[u]; i != -1; i = e[i].next)///结束条件,有时候是i != -1,有时候是i != 0
94 {
95 v = e[i].to;
96 if(!visit[v]) ///如果节点v与u相邻并且未被查找过
97 {
98 visit[v] = true; ///标记v为已查找过
99 if(match[v] == -1 || dfs(match[v])) ///如果i未在前一个匹配M中,或者i在匹配M中,但是从与i相邻的节点出发可以有增广路径
100 {
101 match[v] = u; ///记录查找成功记录,更新匹配M(即“取反”)
102 return true; ///返回查找成功
103 }
104 }
105 }
106 return false;
107 }
108 int Maxmatch()
109 {
110 int sum=0;
111 memset(match,-1,sizeof(match));
112 for(int i = 1 ; i <= m + n ; i++)
113 {
114 memset(visit,false,sizeof(visit)); ///清空上次搜索时的标记
115 if(dfs(i)) ///从节点i尝试扩展
116 {
117 sum++;
118 }
119 }
120 return sum;
121 }
122 int main()
123 {
124 int T;
125 scanf("%d",&T);
126 while (T--)
127 {
128 init();
129 printf("%d\n",m - Maxmatch());
130 if(T)
131 printf("\n");
132 }
133 return 0;
134 }
人生就像心电图,想要一帆风顺,除非game-over