ZOJ-3471-Most Powerf状压dp

Most Powerful-ZOJ-3471动态规划-状压dp

Description

Recently, researchers on Mars have discovered N powerful atoms. All of them are different. These atoms have some properties. When two of these atoms collide, one of them disappears and a lot of power is produced. Researchers know the way every two atoms perform when collided and the power every two atoms can produce.

You are to write a program to make it most powerful, which means that the sum of power produced during all the collides is maximal.

Input

There are multiple cases. The first line of each case has an integer N (2 <= N <= 10), which means there are N atoms: A1, A2, … , AN. Then N lines follow. There are N integers in each line. The j-th integer on the i-th line is the power produced when Ai and Aj collide with Aj gone. All integers are positive and not larger than 10000.

The last case is followed by a 0 in one line.

There will be no more than 500 cases including no more than 50 large cases that N is 10.

Output

Output the maximal power these N atoms can produce in a line for each case.

Examples

Input

2
0 4
1 0
3
0 20 1
12 0 1
1 10 0
0

Output

4
22

Problem description

有n种气体,每种气体之间能发生碰撞,并产生能量,i与j碰撞,j消失,j与i碰撞,i消失,并且两种碰撞产生的能量不同,将各种碰撞组合以矩阵的方式给你,i行j列的数表示i与j碰撞,j消失所产生的能量。

问,它们如何碰撞才能使所有产生的能量总和最大。

Solution

状压dp

>dp[i]i> > 定 义 d p [ i ] 表 示 在 第 i 个 状 态 所 能 获 得 的 最 大 能 量 。 >

状态 i 用2进制表示,比如 n 等于 4 时,1100 (从右往左)表示第2种和第3种气体消失,剩余第0种和第1种气体。

那么下一次碰撞有两种选择,即用第1种气体碰撞第0种,或者用第0种碰撞第1种,状态转移方程分别为:

>dp[(1101)]=dp[13]=max(dp[13],dp[(1100)]+a[1][0]);> > d p [ ( 1101 ) ] = d p [ 13 ] = m a x ( d p [ 13 ] , d p [ ( 1100 ) ] + a [ 1 ] [ 0 ] ) ; >

>dp[(1110)]=dp[14]=max(dp[14],dp[(1100)]+a[0][1]);> > d p [ ( 1110 ) ] = d p [ 14 ] = m a x ( d p [ 14 ] , d p [ ( 1100 ) ] + a [ 0 ] [ 1 ] ) ; >

>a[i][j]ij> > a [ i ] [ j ] 表 示 用 第 i 种 气 体 碰 撞 第 j 种 气 体 所 产 生 的 能 量 >

所以我们可以知道,状态转移就是枚举所有可能的下一次碰撞,根据状态的变化关系由由上一个状态求得当前状态的最优值。

总的状态转移方程:

>dp[i|(1<<j)]=max(dp[i|(1<<j)],dp[i]+a[k][j])ijk> > d p [ i | ( 1 << j ) ] = m a x ( d p [ i | ( 1 << j ) ] , d p [ i ] + a [ k ] [ j ] ) , i 为 上 一 次 的 状 态 , j , k 为 找 到 的 两 种 未 消 失 的 气 体 >

Code

/*
 * @Author: Simon 
 * @Date: 2018-08-14 09:32:57 
 * @Last Modified by: Simon
 * @Last Modified time: 2018-08-14 11:09:24
 */
#include <bits/stdc++.h>
using namespace std;
typedef int Int;
#define int long long
#define INF 0x3f3f3f3f
#define maxn 15
int a[maxn][maxn];
int dp[1 << 11]; //状态为i时所获得的最大能量
Int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    while (cin >> n && n)
    {
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                cin >> a[i][j]; //i碰撞j,j消失所获得的能量
            }
        }
        int ans = 0;
        for (int i = 0; i < (1 << n); i++)
        {
            for (int j = 0; j < n; j++) //枚举每一个位置的气体,找到一个未消失的其他
            {
                if ((i & (1 << j)) != 0)
                    continue;               //如果当前比特位的值为1,代表此气体已消失,跳过此状态
                for (int k = 0; k < n; k++) //再找一个还未消失的气体
                {
                    if ((i & (1 << k)) == 0 && j != k) //第一个判断,同j,还要保证两个气体不是同一个
                        dp[i | (1 << j)] = max(dp[i | (1 << j)], dp[i] + a[k][j]);
                    ans = max(ans, dp[i | (1 << j)]); //所有状态里找最大的
                }
            }
        }
        cout << ans << endl;
    }
    cin.get(), cin.get();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值