POJ2724 Purifying Machine二分图,最小边覆盖

来源:互联网 发布:淘宝店铺怎么开通花呗支付 编辑:程序博客网 时间:2024/05/21 00:52

        题目大意是,2^N个奶酪,编号从二进制0000..00到1111..11,现在有台机器有N个开关,每个开关有3种状态,为1,0,*,同时最多只有一个*存在,*可以替代0,1这两种状态,一个清楚操作则是这台机器状态对应的数和奶酪编码(一个或两个),如001*,则对应0011和0010。现在需要清除指定的几个奶酪,并且不能清楚到指定编码意外的奶酪,求最少需要切换多少次状态。

        二分图,先建模,将指定的编号之间可以由一种状态同时清楚的进行连边,如果某个点没有其它边与其相连,我们可以假设它与某个无穷大的点进行连边,并且这条边当作是隐形的,不在原图范围内,即将问题转化为最少的边覆盖到所有编号。如果直接对该图求最大匹配数,则还需要确定哪些点属于左图或者右图,为了方便起见,我们将所有的编号分别作为左图和右图求最大匹配数P,这个最大匹配数是原图的2倍,因此,最终结果即为 ans = |V| - P / 2。

        下面用的是邻接矩阵的匈牙利算法(这样没有超时,所以就直接用邻接矩阵了)求最大匹配。

#include <stdlib.h>#include <stdio.h>#include <vector>#include <math.h>#include <string.h>#include <string>#include <iostream>#include <queue>#include <list>#include <algorithm>#include <stack>#include <map>#include<iostream>  #include<cstdio>  using namespace std;#define MAXM 1001#define MAXN 11char Infected[MAXN];int InfectedIndex[2048];int BinG[2048][2048];bool Visited[2048];int Result[2048];bool dfs(int s, int n){for (int i = 0; i < n; i++){if (!Visited[i] && BinG[s][i] > 0){Visited[i] = true;if (Result[i] == -1 || dfs(Result[i], n)){Result[i] = s;return true;}}}return false;}int MaxBin(int n){int res = 0;for (int i = 0; i < n; i++){Result[i] = -1;}for (int i = 0; i < n; i++){memset(Visited, 0, sizeof(Visited));if (dfs(i, n)){res++;}}return res;}int main(){#ifdef _DEBUGfreopen("d:\\in.txt", "r", stdin);#endifint N, M;int tmpVec[2048];while (scanf("%d %d", &N,&M) != EOF){//tmpVec.clear();memset(InfectedIndex, 0, sizeof(InfectedIndex));memset(BinG, 0, sizeof(BinG));if (N == 0 && M == 0){break;}int index = 0;for (int i = 0; i < M;i++){scanf("%s\n", Infected);int a, b;b = -1;a = 0;for (int k = N - 1; k >= 0; k--){if (Infected[k] == '1'){a |= (1 << (N - k - 1));if (b >= 0){b |= (1 << (N - k - 1));}}else if (Infected[k] == '*'){b = a;a |= (1 << (N - k - 1));}}if (InfectedIndex[a] == 0){tmpVec[index++] = a;//tmpVec.push_back(a);}if (b >= 0 && InfectedIndex[b] == 0){tmpVec[index++] = b;//tmpVec.push_back(b);}InfectedIndex[a] = 1;if (b >= 0){InfectedIndex[b] = 1;}}for (int i = 0; i < index;i++){for (int j = i + 1; j < index;j++){int count = 0;for (int k = 0; k < N; k++){if ((tmpVec[i] & (1 << k)) == (tmpVec[j] & (1 << k))){count++;}}if (count == N - 1){BinG[i][j] = 1;BinG[j][i] = 1;}}}int iMaxBin = MaxBin(index);int res = index - iMaxBin / 2;printf("%d\n", res);}return 0;}


4 0