zoukankan      html  css  js  c++  java
  • NOIP 2017宝藏(状压DP)

    70分做法:

    全排列,再枚举这个点由那个点扩展出来的即可。

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int maxm=2007;
    const int inf=1e9+7;
    int dis[20][20];
    int l[20],ans=1e9+7;//到i记录经过的点数 
    int n,m;
    void dfs(int sum,int num)
    {
      if(sum>ans)
      return;
      if(num==n)
      ans=sum;
      for(int i=1;i<=n;i++)
      {
       if(l[i]) continue;
       for(int j=1;j<=n;j++)//枚举由哪个直接相连的点扩展过来 
       {
         if(!l[j]||i==j||dis[j][i]==inf) continue;
         int tmp=sum+l[j]*dis[j][i];
         l[i]=l[j]+1;
         dfs(tmp,num+1);
         l[i]=0;
       }
      }
    }
    int main()
    {
     scanf("%d%d",&n,&m);
     memset(dis,inf,sizeof(dis));
     for(int i=1;i<=m;i++)
     {
       int x,y,z;
       scanf("%d%d%d",&x,&y,&z);
       if(dis[x][y]>z)dis[x][y]=dis[y][x]=z;
     }
     for(int i=1;i<=n;i++)
     {
      l[i]=1;
      dfs(0,1);
      l[i]=0;
     }
     printf("%d
    ",ans);
     return 0;	
    }
    

    满分做法:

    (n<=12),考虑状压DP。首先我们会考虑到(dp[S])表示S状态下的代价,但因为本题的代价是动态的,所以不好转移。

    但因为最后挖通的道路连成的图一定是一棵树,我们可以再加一维(dp[k][S]),表示第K层状态为(S)的代价,此时的层也就是深度,转移时把扩展的边权和乘(k-1)即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxm=(1<<12)+7;
    const int inf=1e9+7; 
    ll dis[maxm][maxm];//dis[i][j]从i状态转移到j的最短路径总长 
    ll dp[15][maxm];//dp[k][j] 到了第j层状态为j的代价
    ll len[15][15];
    int n,m;
    int main()
    {
     scanf("%d%d",&n,&m);
     memset(len,inf,sizeof(len));
     memset(dp,inf,sizeof(dp)); 
     for(int i=1;i<=m;i++)
     {
       int x,y,z;
       scanf("%d%d%d",&x,&y,&z);
       if(z<len[x][y])
       len[x][y]=len[y][x]=z;
     }
     for(int i=0;i<(1<<n);i++)
     {
      for(int j=i;j;j=(j-1)&i)//枚举i的子集
      {
       int bu=i^j;//j的补集
       bool flag=0;
       ll minn;
       for(int k=1;k<=n;k++)
       {
       	if((1<<(k-1))&bu)//哪个点还没有走过 
       	{
       	   minn=inf;
       	   for(int p=1;p<=n;p++)//寻找已经找过的点,能否向这个点扩展
    	   {
    	      if((1<<(p-1))&j)
    		  minn=min(minn,len[p][k]);
    	   }
    	   if(minn==inf)
    	   {
    	   	 flag=1;
    	   	 break;
    	   }
    	   dis[j][i]+=minn;
       	}
       }
       if(flag)
       dis[j][i]=inf;
      } 
     }
     for(int i=1;i<=n;i++)//根节点免费 
     dp[1][1<<(i-1)]=0;
     for(int k=2;k<=n;k++)
     {
      for(int i=0;i<(1<<n);i++)
      {
       for(int j=i;j;j=(j-1)&i)
       {
         if(dis[j][i]!=inf)
    	 dp[k][i]=min(dp[k][i],dp[k-1][j]+(k-1)*dis[j][i]);	
       }
      }
     }
     ll ans=inf;
     for(int i=1;i<=n;i++)
     ans=min(ans,dp[i][(1<<n)-1]);
     printf("%lld
    ",ans);
     return 0;	
    }
    
  • 相关阅读:
    OpenSSL生成证书、密钥
    js中对String去空格
    正则表达式
    webapi调用
    记一次完整的CI持续集成配置过程(.net core+Jenkins+Gitea)
    处理asp.net core连接mysql的一个异常Sequence contains more than one matching element
    asp.net core 3.1+mysql8.0+Hangfire遇到的异常解决记
    升级到asp.net core 3.1遇到的json异常
    了解ASP.NET Core端点路由
    asp.net core 2.2升到3.1遇到的问题小记
  • 原文地址:https://www.cnblogs.com/lihan123/p/11663534.html
Copyright © 2011-2022 走看看