宝藏(NOIP2017)

题目链接:点击打开链接

题目分析:

    考场上,这个只搞了45分,可以有人用A* A了啊。我们对于遍历过的节点i我们标记为1,对于没有标记过的节点我们标记为0;然后我们用一串二进制数来表示当前局面的状态,用dp[i]表示遍历完当前二进制中1的位所表示的节点所用的最小花费。

我们先枚举每一个点作为起点,然后我们开始dfs,我们枚举当前dfs到的状态所表示的遍历过的节点,然后我们枚举所有与这些节点相邻的节点,并且判断是否可以更新,最后再回溯;

代码放上

#include 
#include 
#include 
#include 
#define inf 2147483647
using namespace std;
int dp[1<<13],dis[15],G[15][15],isG[15][15],n,m,ans=inf;
void Add_(int x,int y,int w)
{	
	G[x][y]=w;
	G[y][x]=w;
	isG[x][y]=1;
	isG[y][x]=1;//右边
}
void dfs(int x)
{
    for(int i=1;i<=n;i++)//枚举节点看看当前的状态是否被遍历过
	{
        if((1<<(i-1))&x)//被遍历过了就开始以当前节点为起点进行遍历
	    {
            for(int j=1;j<=n;j++)
			{
                if(!(1<<(j-1)&x)&&isG[i][j])//如果有边并且在dfs到的状态里没有被遍历
                    if(dp[1<<(j-1)|x]>dp[x]+dis[i]*G[i][j])//满足更新,其中| 在二进制中相当于状态相加
		    {
                        int temp=dis[j];
                        dis[j]=dis[i]+1;//深度加一
                        dp[1<<(j-1)|x]=dp[x]+dis[i]*G[i][j];//更新
                        dfs(1<<(j-1)|x);//继续dfs加上x状态
                        dis[j]=temp;
                    }
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    memset(G,63,sizeof(G));
    for(int i=1;i<=m;i++)
	{
        int x,y,w;scanf("%d%d%d",&x,&y,&w);
        if(w	{
        memset(dis,63,sizeof(dis));
        for(int j=1;j<=(1<

你可能感兴趣的:(状压Dp)