BUPT Summer Journey #test6 B

 

B. 高兴 2014新生暑假个人排位赛06

时间限制 4000 ms     内存限制 65536 KB    

题目描述

小弱有n个玩具,现在小弱想把他们排列成一行,把玩具j放在玩具i的右边相邻的位置上,他将得到一个高兴值Hij.

输入格式

输入有多组数据。
每组数据以一个整数n(n <= 18)开头。
接下来n行, 每行n个整数。 第i行第j列Hij( Hij的绝对值 <= 10000)代表把玩具j放在玩具i的右边相邻的位置时高兴值。输入保证Hii = 0,最左边只考虑与右边相邻的玩具,最右边只考虑与左边相邻的玩具。

 

输出格式

对于每组数据输出最大高兴值。

输入样例

2
0 1
2 0
3
0 -1 7
3 0 3
3 3 0

输出样例

2 
10

 

思路:其实要求最大的高兴值可以归结于从某个点出发遍历一遍图所得到的最大权值。即旅行商人问题。dp[i][S]从i出发遍历一遍集合S中的节点的最大收益,dp[i][S]=max(dp[j][S^(1<<j)]+h[i][j])(j∈S).注意最大值不要定太大否则会超。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctype.h>
#define LOCAL
using namespace std;
int n,ans;
int h[30][30];
int dp[18][1<<18],vis[18][1<<18];
void DP(int i,int S)
{
    //printf("i=%d S=%d vis[%d][%d]=%d\n",i,S,i,S,vis[i][S]);system("pause");
    //if(vis[i][S])return;
    if(S==0){dp[i][S]=0;vis[i][S]=1;return;}
    vis[i][S]=1;dp[i][S]=-2000000000;
    for(int j=0;j<n;j++)
        if(((1<<j)&S)!=0)
        {
            //printf("j=%d\n",j);
            if(!vis[j][S^(1<<j)])DP(j,S^(1<<j));
            dp[i][S]=max(dp[j][S^(1<<j)]+h[i][j],dp[i][S]);
        }
    return;
}
int main()
{
    #ifdef LOCAL
    freopen("input.txt","r",stdin);
    #endif // LOCAL
    while(scanf("%d",&n)==1)
    {
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)scanf("%d",&h[i][j]);
        //for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%d ",h[i][j]);cout<<endl;}
        //for(int i=1;i<=n;i++)dp[i][0]=0;
        //memset(dp,0,sizeof(dp));
        //printf("%d\n",1&12);
        memset(vis,0,sizeof(vis));
        //memset(dp,)
        int S=(1<<n)-1;
        //for(int i=1;i<=n;i++)S=S|(1<<i);
        //printf("S=%d\n",S);
        for(int i=0;i<n;i++)DP(i,S^(1<<i));
        int ans=-2000000000;
        for(int i=0;i<n;i++)if(ans<dp[i][S^(1<<i)])ans=dp[i][S^(1<<i)];
        //for(int i=0;i<n;i++){printf("%d\n",dp[i][S^(1<<i)]);}
        printf("%d\n",ans);
    }
    return 0;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值