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 }
二分图匹配

 

 

 

 

posted @ 2015-09-04 23:31  一麻袋码的玛侬  阅读(160)  评论(0编辑  收藏  举报