标签:状态 Task 连线 Simple lowbit ll CF int
【状态压缩DP】CF D. A Simple Task求环的个数
铺垫
二进制的一些操作
寻找第一个1 lowbit
lowbit是树状数组中的老熟人了,原理是运用了原码和补码的特性。
int inline lowbit(int x)
{
return x&(-x)
}
合并状态 利用|运算
sta1|sta2
查找第k位上的数字是1,还是0
(s>>k)&1
思路
我们可以用一串01数字,来表示各个位置的占用情况。
比如101001,(1表示灯亮,0表示灯灭),故而在这里,我们可以知道1、3、6号灯处于亮的状态,2、4、5号灯处于灭的状态。
因而,我们可以定义一个二维dp数组d[i][j]
,数字i用来表示当前连线的点,j代表当前连线的终点,d[i][j]
表示拥有状态i表示的点的集合且以点j为结尾的连线的个数。
同时为了避免重复,我们对起点进行枚举。
举个例子,我们可以对加入公司的员工按ta们的起始工资进行分类,这样的分类方式,必然不会出现重复。
(在代码实现中,若新加入的点小于起点的编号,那么就不考虑该点的加入)
- 其他
- ABC(A)和ACB(A)这两个环本质上是一样的
- ABA不符合题目标准,且在dp过程中有且仅有会产生m个
- 因而,需要对答案进行修正,(ans-m)/2.
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 20 ;
ll d[1<<N][N],g[N][N],n;
ll maxn,m,q;
int inline lowbit(int x)
{
return x&(-x);
}
void init()
{
cin>>n;
maxn = (1<<n)-1;
cin>>m;
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
a--;b--;
g[a][b] = g[b][a] = 1;
}
for(int i=0;i<n;i++)
d[1<<i][i] = 1;
}
ll dp()
{
ll ans = 0;
for(int i=0;i<=maxn;i++)//状态从小到大进行枚举,也保证了正常的顺序
{
int t = lowbit(i);
for(int j=0;j<n;j++) //枚举状态i的结尾顶点
if(!d[i][j] || (1<<j)<t) continue;//不存在和小于起点,直接跳过
else for(int k=0;k<n;k++) //尝试去接上新的点
{
if(!g[j][k]||(1<<k)<t) continue;//如果不导通或者小于起点,直接跳过。
if( (i>>k)&1 )
{
if( t == (1<<k) )
ans += d[i][j];
}
else
d[ (1<<k)|i ][k] += d[i][j];
}
}
ans = (ans-m)/2;
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
init();
cout<<dp();
return 0;
}
标签:状态,Task,连线,Simple,lowbit,ll,CF,int 来源: https://www.cnblogs.com/BeautifulWater/p/15806846.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。