题意:
有2^N块奶酪,编号为00...0到11..1。
有一台机器,有N个开关。每个开关可以置0或置1,或者置*。但是规定N个开关中最多只能有一个开关置*。
一旦打开机器的开关,机器将根据N个开关的状态对状态对应的编号的奶酪进行消毒。
例如:111 --> 对编号111的奶酪进行消毒。 说明:*代表0或1。 例如:1*1 --> 对编号为101和111的奶酪进行消毒。
现在有一些奶酪被污染了。给出这些奶酷的编号。
问最少需要几次对机器进行设定,使得所有的奶酪都被消毒。
思路:
一个带*的状态可以对两块奶酪进行杀毒。如果两块奶酪都没被之前的操作消过毒,那么这个状态是可以减少机器操作数的。所以这个带*的状态一定要操作的。
则我们要尽量地多找带*的状态,每一种状态消毒的两块奶酪都没有被其它带*的操作消过毒。二分图模型若隐若现了。
要消毒的奶酷复制一份,左边一份,右边一份,如果左边集合的某块奶酪编号和右边集合的某块奶酪编号差一位,则它们可以通过一次操作进行消毒。
求二分图的最大匹配M。
答案: 要消毒的奶酪块数 - M/2
*(未解决):有一个东西不知道咋证。就是这个最大匹配为啥一定就是2倍的关系。
可不可能存在:假设(1-2,3 2-1,3 3-1,2) (1-2,3,4 2-1,3,4 3-1,2,4 4-1,2,3)
1-2 2-3 3-1 这样的情况。(正确应该是1-2 2-1) 或者 1-2 2-3 3-4 4-1 (虽然可以调整为1-2 2-1 3-4 4-3)
代码:
int n,m,c; char s[15]; bool ex[2005]; int num[2005]; vector<int> graph[2005]; bool bmask[2005]; int cx[2005],cy[2005]; int findPath(int u){ int L=graph[u].size(); rep(i,0,L-1){ int v=graph[u][i]; if(!bmask[v]){ bmask[v]=true; if(cy[v]==-1||findPath(cy[v])){ cy[v]=u; cx[u]=v; return 1; } } } return 0; } int MaxMatch(){ int ans=0; rep(i,1,c) cx[i]=cy[i]=-1; rep(i,1,c) if(cx[i]==-1){ mem(bmask,false); ans+=findPath(i); } return ans; } bool OneDigit(int x,int y){ int f=0; while(x||y){ f+=((x&1)!=(y&1)); x>>=1, y>>=1; } if(f==1) return true; else return false; } int main(){ while(scanf("%d%d",&n,&m)!=EOF,n||m){ mem(ex,false); c=0; rep(i,1,2*m) graph[i].clear(); rep(i,1,m){ scanf("%s",s); int ts1=0,ts2=0; rep(j,0,n-1){ ts1*=2; ts2*=2; if(s[j]!=‘*‘) ts1+=(s[j]-‘0‘), ts2+=(s[j]-‘0‘); else ts1+=0, ts2+=1; } if(!ex[ts1]) { num[++c]=ts1; ex[ts1]=true; } if(!ex[ts2]) { num[++c]=ts2; ex[ts2]=true; } } rep(i,1,c) rep(j,1,c){ if(OneDigit(num[i],num[j])) graph[i].push_back(j); } int dd=MaxMatch()/2; printf("%d\n",c-dd); } }
时间: 2024-11-10 17:41:11