Codeforces Round 937 (Div. 4)G. Shuffling Songs 状压dp,状压记忆化的dfs

Problem - G - Codeforces

我的暴力dfs超时了,看了官方题解写了状压dp.

官方题解是正向延伸dp的。

我的是"从后往前确认"dp的。

另外预处理我没有做排序,而是直接暴力匹配的。

目录

状压dp:

剪枝的dfs:


状压dp:

vector<string>genres;
vector<string>writers;
int n;
int gsame[17][17];
int wsame[17][17];
int bitcnt(unsigned aim)
{
	int ret = 0;
	while (aim)
	{
		if (aim & 1)
			ret++;
		aim >>= 1;
	}
	return ret;
}
void solve()
{
	memset( gsame,0,sizeof gsame );
	memset( wsame,0,sizeof wsame );
	
	cin >> n;
	genres = writers = vector<string>(n);
	for (int i = 0; i < n; i++)
	{
		cin >> genres[i] >> writers[i];
	}
	//预处理字符串是否相等
	for (int i = 0; i < n; i++)
	{
		for (int j = i+1; j < n; j++)
		{
			if (genres[i] == genres[j])
				gsame[i][j] = gsame[j][i] = 1;
			if (writers[i] == writers[j])
				wsame[i][j] = wsame[j][i] = 1;
		}
	}
	//一维是状态,二维是此刻尾部是第几个,dp为1代表这种状态可取
	vector<vector<int>>dp(1<<n, vector<int>(n));
	//初始化
	for (int i = 0; i < n; i++)
	{
		dp[1 << i][i] = 1;
	}
	//遍历所有情况
	for (int mask = 0; mask < (1 << n); mask++)
	{
		for (int i = 0; i < n; i++)
		{
			if (mask >> i&1)
			{
				int lastm = mask - (1 << i);
				for (int j = 0; j < n; j++)
				{
					if (lastm >> j&1)
					{
						if (dp[lastm][j] == 1&&(gsame[i][j] || wsame[i][j]))
						{
								dp[mask][i] = 1;
								break;
						}
					}
				}
				//if (dp[mask][i])break;每个合法的i都要测试到
			}
		}
	}
	int ans = 0;
	for (int mask = 0; mask < (1 << n); mask++)
		for (int i = 0; i < n; i++)
			if (dp[mask][i])
				ans = max(ans, bitcnt(mask));

	cout << n - ans << endl;
}

剪枝的dfs:

vector<string>genres;
vector<string>writers;
int ans;
int vis[17];
int mem[1 << 16][16];//剪枝
int n;
int gsame[17][17];
int wsame[17][17];
void dfs(int aim, int cur,int mask)
{
	if (mem[mask][aim])return;
	mem[mask][aim] = 1;
	ans = max(ans, cur);

	for (int i = 0; i < n; i++)
	{
		if (vis[i] == 0 && (gsame[i][aim] || wsame[i][aim]))
		{
			vis[i] = 1;
			dfs(i, cur + 1,mask|(1<<i));
			vis[i] = 0;
		}
	}
}
void solve()
{
	memset(vis, 0, sizeof vis);
	memset(gsame, 0, sizeof gsame);
	memset(wsame, 0, sizeof wsame);
	memset(mem, 0, sizeof mem);
	ans = 1;

	cin >> n;
	genres = writers = vector<string>(n);
	for (int i = 0; i < n; i++)
	{
		cin >> genres[i] >> writers[i];
	}
	//预处理字符串是否相等
	for (int i = 0; i < n; i++)
	{
		for (int j = i + 1; j < n; j++)
		{
			if (genres[i] == genres[j])
				gsame[i][j] = gsame[j][i] = 1;
			if (writers[i] == writers[j])
				wsame[i][j] = wsame[j][i] = 1;
		}
	}
	for (int i = 0; i < n; i++)
	{
		vis[i] = 1;
		dfs(i, 1,1<<i);
		vis[i] = 0;
	}

	cout << n - ans << endl;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值