题目链接:https://www.luogu.com.cn/problem/P2196

大意:有n个地窖,每个地窖里有一些地雷,给出第i个地窖到i+1 - n的连通性。求出最优解及路径,要求拆除地雷最多。

这个题可以爆搜(因为n的值很小),也可以dp(类似于最长子序列那种,这里不同的是需要考虑连通性)

这个题看着不难但是自己dfs写的并不是很好,所以wa了,dp做法也看不出来个之所以然

这个题也没有很多需要注意的地方,可能dp写法的状态转移和表示是需要好好分析一下的,其实就是看爆搜的水平和一些dp的分析,这两个确确实实都是我的弱项。emm~代码还是挺简单的,这里的dpi表示为以i为终点的最优解。i受到的影响应该是前几个节点。这样就从i-1到1来转移到dpi。可以看到我们转移状态的时候是用前面的状态来转移的,所以外循环要从小到大开始,把之前的最优子状态算好了,再推导我们之后的状态。

爆搜code:

#include<bits/stdc++.h>
using namespace std;
int cellar[25],mapt[25][25],path[25],ans[25];
int n,k,maxt = 0,cnt;
bool sign[25];

bool check(int x)
{
	for(int i=1;i<=n;i++)
		if(mapt[x][i]&&!sign[i])	return false;
	return true;
}
void dfs(int x,int step,int sum)
{
	if(check(x))
	{
		if(sum>maxt)
		{
			memcpy(ans,path,sizeof path);
			maxt = sum;
			cnt = step-1;
		}
		return;
	}
	for(int i=1;i<=n;i++)
		if(mapt[x][i]&&!sign[i]) 
		{
			sign[i] = true; path[step] = i;
			dfs(i,step+1,sum+cellar[i]);
			sign[i] = false;
		}	
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&cellar[i]);
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		scanf("%d",&k);
		if(k)	mapt[i][j] = 1; else	mapt[i][j] = 0;
	}
	for(int i=1;i<=n;i++)
	{
		sign[i] = true;
		path[1] = i;
		dfs(i,2,cellar[i]);
	}
	for(int i=1;i<=cnt;i++)
		printf("%d%c",ans[i],i==cnt?'\n':' ');
	printf("%d",maxt);
}

dpcode:

#include<bits/stdc++.h>
using namespace std;
int cellar[25],mapt[25][25],path[25],ans[25];
int n,k,maxt = 0,cnt;
bool sign[25];

bool check(int x)
{
	for(int i=1;i<=n;i++)
		if(mapt[x][i]&&!sign[i])	return false;
	return true;
}
void dfs(int x,int step,int sum)
{
	if(check(x))
	{
		if(sum>maxt)
		{
			memcpy(ans,path,sizeof path);
			maxt = sum;
			cnt = step-1;
		}
		return;
	}
	for(int i=1;i<=n;i++)
		if(mapt[x][i]&&!sign[i]) 
		{
			sign[i] = true; path[step] = i;
			dfs(i,step+1,sum+cellar[i]);
			sign[i] = false;
		}	
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&cellar[i]);
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		scanf("%d",&k);
		if(k)	mapt[i][j] = 1; else	mapt[i][j] = 0;
	}
	for(int i=1;i<=n;i++)
	{
		sign[i] = true;
		path[1] = i;
		dfs(i,2,cellar[i]);
	}
	for(int i=1;i<=cnt;i++)
		printf("%d%c",ans[i],i==cnt?'\n':' ');
	printf("%d",maxt);
}