SRM 549 OrderOfTheHats

来源:互联网 发布:数据库系统基础 6 pdf 编辑:程序博客网 时间:2024/06/06 16:38

题意

孩子们有N(1<=N<=20)个音标要去学,按照一般的教学法则,每次学一个音标的时候,要先把比这个音标更基础的音标学会。但由于这个教学法则会出现循环需要的情况导致孩子们无法学完,请你帮助他们用最少的次数改变这个教学法则。

给定一个vectorspellchart,spellchart[i][j]表示如果为’Y’则音标i必须在j前学习完,否则为’N’。你可以将’Y’改成’N’或者’N’改成’Y’,但每个位置只能改变一次。输出最少次数。

思路

<1>很容易想到将每个i,j用图链接形成一个有向图
<2>我们的目标是通过增减边将其变成一个有向无环图(且在对于边的操作中很显然不需要添加边)
<3>如果需要连接两个点(使这两个点合法)需要满足:A-B中没有相互联通的两条边(可以没有边)》
<4>由于只有20个点可以使用状态压缩dp[has]表示形成该点集的最小cost
<5>转移:使点集has中加上一个点i得到新的点集nx是需要将i通向点集has所有的边都删除
得到dp[nw]=min(dp[nw]+dp[nx]+need_change(nx,i));
<6>nx&to[i]数中1的个数即为i可以 到nx中点的个数(利用二进制来表示to[i])

    int need_change(int x){        int cnt=0;        while(x){if(x&1)cnt++;x>>=1;}        //while(x){x-=x&(-x);cnt++;}        //while(x){x=x&(x-1);cnt++;}        return cnt;    }    int dfs(int has){        if(has==(1<<n)-1)return 0;        int &ans=dp[has];        if(~ans)return ans;        ans=INF;        for(int i=0;i<n;i++)        if(!(has&(1<<i))){//没有该点             int nx=has+(1<<i);            ans=min(ans,need_change(nx&to[i])+dfs(nx));             //need_chage(nx&to[i])            //表示再加上i点后通过i点的路径可以回到nx中点的个数(即需要删掉边的个数 )         }return ans;    }
        n=A.size();        memset(dp,-1,sizeof(dp));        for(int i=0;i<n;i++){            to[i]=0;//利用二进制储存i可以到的点             for(int j=0;j<n;j++)            if(A[i][j]=='Y')to[i]+=1<<j;        }return dfs(0);    }};
3 0
原创粉丝点击