poj 2288 Islands and Bridges ——状压DP

题目:http://poj.org/problem?id=2288

状压挺明显的;

一开始写了(记忆化)搜索,但一直T;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const inf=0x3f3f3f3f;
int T,n,m,v[15];
ll ans,cnt,f[1<<13];
bool mp[15][15];
void dfs(int z,int x,int y,ll w)
{
    if(w<f[z])return;
    f[z]=w;
    if(z==(1<<n)-1)
    {
        if(w>ans)ans=w,cnt=1;
        else if(w==ans)cnt++;
        return;
    }
    for(int i=1;i<=n;i++)
        if((z&(1<<(i-1)))==0)
            dfs(z|(1<<(i-1)),y,i,w+v[i]+v[y]*v[i]+(mp[x][i]?v[x]*v[y]*v[i]:0));
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        memset(f,0,sizeof f);
        memset(mp,0,sizeof mp);
        ans=-inf; cnt=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&v[i]);
        for(int i=1,x,y;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            mp[x][y]=1; mp[y][x]=1;
        }
        dfs(0,0,0,0);
        if(cnt==0)printf("0 0\n");
        else printf("%lld %lld\n",ans,cnt/2);
    }
    return 0;
}

于是改成刷表,注意点细节就行了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const inf=0x3f3f3f3f;
int T,n,m,v[15];
ll ans,cnt,f[1<<13|1][15][15],s[1<<13|1][15][15];
bool mp[15][15];
void dp()
{
    memset(f,-1,sizeof f);
    memset(s,0,sizeof s);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)    if(mp[i][j])
        {
            int p=((1<<(i-1))|(1<<(j-1)));
            f[p][i][j]=v[i]+v[j]+v[i]*v[j]; s[p][i][j]=1;
        }
    for(int p=3;p<(1<<n);p++)
        for(int i=1;i<=n;i++)    if(!(p&(1<<(i-1))))
            for(int j=1;j<=n;j++)    if(p&(1<<(j-1)))
                for(int k=1;k<=n;k++)     if((p&(1<<(k-1)))&&j!=k&&mp[i][k]&&f[p][j][k]!=-1)
                {
                    ll tmp=f[p][j][k]+v[i]+v[k]*v[i]+(mp[j][i]?v[j]*v[k]*v[i]:0);
                    int tp=(p|(1<<(i-1)));
                    if(tmp>f[tp][k][i]) f[tp][k][i]=tmp,s[tp][k][i]=s[p][j][k];
                    else if(tmp==f[tp][k][i])s[tp][k][i]+=s[p][j][k];
                }
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        memset(mp,0,sizeof mp);
        ans=-inf; cnt=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&v[i]);
        for(int i=1,x,y;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            mp[x][y]=1; mp[y][x]=1;
        }
        if(n==1){printf("%d %d\n",v[1],1); continue;}//
        dp(); int mx=(1<<n)-1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)    if(i!=j)
            {
                if(f[mx][i][j]==ans)cnt+=s[mx][i][j];
                else if(f[mx][i][j]>ans)ans=f[mx][i][j],cnt=s[mx][i][j];
            }
        if(cnt==0)printf("0 0\n");//
        else printf("%I64d %I64d\n",ans,cnt/2);//
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/9367593.html

时间: 2024-10-07 11:35:54

poj 2288 Islands and Bridges ——状压DP的相关文章

poj2288(Islands and Bridges) 状压DP

题目链接:http://poj.org/problem?id=2288 题意:每个点有一个权值Vi,找一条哈密顿路径,路径的权值来自三条:1 路径上的Vi之和 2 所有相邻点对ij的Vi*Vj之和 3 相邻连续三点i,j,k(并且三点要构成三角形)Vi*Vj*Vk之和. 解法:dp[st][i][j]表示从j走到i并且剩下集合st没有走的最大权值.关于路径书,在转移的时候顺便计算即可:这道题令自己恶心了好久,最后原因是自己犯了一个严重错误,题目读错了,没有读到Vi*Vj*Vk要保证ijk能够构成

POJ 2288 Islands And Bridges 状态压缩dp+哈密顿回路

题意:n个点 m条边的图,路径价值定义为相邻点乘积,若路路径c[i-1]c[i]c[i+1]中c[i-1]-c[i+1]有边 则价值加上三点乘积找到价值最大的哈密顿回路,和相应的方法数n<=13.暴力dfs O(13!) TLE 由于n<13 经典的状态压缩dp [状态] [当前点位置 ][前一点位置] 注意上一个状态必须合法才能进行转移设状态dp[s][i][j] 当前状态为s,当前点为i上一个点为j的最大价值, ans=max(dp[(1<<n)-1][i])dp[s][i][

POJ 2288 Islands and Bridges 哈密尔顿路 状态压缩DP

找最长的其实是很裸的状态压缩DP,棘手的地方是要统计数量,其实只要再来一个数组存就好. 不过代码比较长,细节要注意的地方毕较多,wa了很多发,还是要仔细啊 用递推和记忆化搜索分别写了一遍 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <

poj 2288 Islands and Bridges

题意: 给你一个双向连通图,求 获得权值最大 的 哈密顿通路的 权值 和 这个权值对应的数目: 其中权值计算方法是  列如 ABCD  权值是a+b+c+d+ab+bc+cd 如果 A,B,C  和B,C,D 可构成三角形分别加上abc,bcd: 这个题 和poj 3311  很相像: 那个需要记录一个最后到达的地方   这个需要记录俩个罢了 DP[i][a][b]其中 i  二进制 中1表示这个点走过了   最后走的的 的是b>>a 因为对于已经走过了{1,2,3,4,,5,6,..,N}

POJ 2411 Mondriaan&#39;s Dream(状压DP)

http://poj.org/problem?id=2411 求一个n*m矩阵用1*2方块去填满的情况有几种 思路:状压dp,先预处理那些状态之间能互相到达,情况就几种,上一个两个1,下一个状态也两个1,上一个为0,下一个必须为1,还有一种是上一个为1,下一个为0的情况 然后就一层层往后递推即可 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int

POJ 2411 Mondriaan&#39;s Dream ——状压DP 插头DP

[题目分析] 用1*2的牌铺满n*m的格子. 刚开始用到动规想写一个n*m*2^m,写了半天才知道会有重复的情况. So Sad. 然后想到数据范围这么小,爆搜好了.于是把每一种状态对应的转移都搜了出来. 加了点优(gou)化(pi),然后poj上1244ms垫底. 大概的方法就是考虑每一层横着放的情况,剩下的必须竖起来的情况到下一层取反即可. 然后看了 <插头DP-从入门到跳楼> 这篇博客,怒抄插头DP 然后16ms了,自己慢慢YY了一下,写出了风(gou)流(pi)倜(bu)傥(tong)

poj 2411 Mondriaan&#39;s Dream 状压dp入门

题意: 求h*w的矩形被1*2的小矩形覆盖的方案数. 分析: 状压dp入门,<挑战程序设计竞赛>上讲的很好,好几天才看懂. 代码: #include <iostream> using namespace std; __int64 ans[16][16]; int n,m; __int64 dp[2][1<<16]; __int64 solve() { int i,j,used; memset(dp,0,sizeof(dp)); __int64 *crt=dp[0],*n

POJ 2411 Mondriaan&#39;s Dream (状压DP)

题意:给出一个n*m的棋盘,及一个小的矩形1*2,问用这个小的矩形将这个大的棋盘覆盖有多少种方法. 析:对第(i,j)位置,要么不放,要么竖着放,要么横着放,如果竖着放,我们记第 (i,j)位置为0,(i+1,j)为1,如果横着放,那么我们记 (i,j),(i,j+1)都为1,然后dp[i][s]表示 第 i 行状态为 s 时,有多少方法,那么我们就可以考虑与和匹配的状态,这个也很容易判断. 代码如下: #pragma comment(linker, "/STACK:1024000000,102

POJ 1185 炮兵阵地(状压DP入门)

http://poj.org/problem?id=1185 状压DP: 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int dp[105][100][100]; 7 int ma[105],st[105]; 8 9 int ok(int x) 10 { 11 return (x&(x<<1))+(x&(x&