SRM 549 OrderOfTheHats

11 篇文章 0 订阅
8 篇文章 0 订阅

题意

孩子们有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);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值