zoj 3471(状态压缩DP,类似于点集配对)

Most Powerful


Time Limit: 2 Seconds      Memory Limit: 65536 KB


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.

Sample Input

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

Sample Output

4
22

解法1:

所有的原子组成一个集合,每次从中选取两个点,选择一个攻击点,选择一个被攻击点,

d[s]=max(d[s],d[s ^ (1<<j)] +a[i][j]);

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define maxn 10
using namespace std;
int d[1<<10]; //表示到达状态s时产生的最大能量
int a[20][20];
int n;
void init()
{
   memset(d,0,sizeof(d));
}
void solve()
{
   for(int s=3;s<(1<<n);s++)
   {
       d[s]=0;
      for(int i=0;i<n;i++)
       if(s & (1<<i))
       {
           for(int j=0;j<n;j++)
            if(s & (1<<j))
           {
               if(i==j)
                continue;
               d[s]=max(d[s],d[s ^ (1<<j)]+a[i][j]);

           }
       }
   }

}
int main()
{
    while(~scanf("%d",&n))
    {
      if(n==0)
        break;
        init();
      for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
      {
          scanf("%d",&a[i][j]);
      }
      solve();
      int ans=0;
    // for(int i=0;i<(1<<n);i++)
     //   cout<<d[i]<<" ";
     //cout<<endl;
      //ans=max(ans,d[i]);
     printf("%d\n",d[(1<<n)-1]);
    }
    return 0;
}

解法2:

假设一个数,第i位表示第i个原子是否被灭掉,如果被灭掉则为1,没被灭掉为0,那么所有状态都可以用2^n范围内的数来表示。则初始状态为0,即所有原子都没有消失

  令dp[i]表示达到状态 i 时所产生的最大能量,则答案就是从0~(1<<n)所有状态里释放的最大的那个能量。 需要枚举所有状态。

  假设当前状态是s,从1~n里边枚举主动碰撞的原子 i ,和被动碰撞被消灭掉的原子 j ,则

  dp[s | (1<<j)] = max{dp[s | (1<<j)] , dp[s] + A[i][j]};

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define maxn 10
using namespace std;
int d[1<<10]; //表示到达状态s时产生的最大能量
int a[20][20];
int n;
void init()
{
    memset(d,0,sizeof(d));
}
void solve()
{
    for(int s=0;s<(1<<n);s++)
    {
     for(int i=0;i<n;i++)
     {
       if( (s & (1<<i))!=0 )
       {
            for(int j=0;j<n;j++)
          {
           if(i==j)
          continue;
           if(s & (1<<j))
           continue;
          d[s |(1<<j)] = max(d[s | (1<<j)],d[s]+a[i][j]);
         }
      }
     }
    }

}
int main()
{
    while(~scanf("%d",&n))
    {
        if(n==0)
        break;
        init();
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
           scanf("%d",&a[i][j]);
        }
        solve();
        int ans=0;
        for(int i=0;i<(1<<n);i++)
        ans=max(ans,d[i]);
        printf("%d\n",ans);

    }
    return 0;
}
时间: 2024-12-22 06:46:36

zoj 3471(状态压缩DP,类似于点集配对)的相关文章

zoj 3471状态压缩DP

#include<stdio.h> #include<string.h> int max(int a,int b) { if(a>b) return a; return b; } int dp[100000],map[15][15],mark[15]; int main() { int i,j,n,m,k; while(scanf("%d",&n)!=EOF&&n) { for(i=1;i<=n;i++) for(j=1;j&

ZOJ3471 状态压缩DP

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3471 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

poj 3311 Hie with the Pie(状态压缩dp)

Description The Pizazz Pizzeria prides itself in delivering pizzas to its customers as fast as possible. Unfortunately, due to cutbacks, they can afford to hire only one driver to do the deliveries. He will wait for 1 or more (up to 10) orders to be

状态压缩DP与TSP问题

状态压缩DP DP过程中的状态不可能像背包问题一样只有整数,肯定有各种各样稀奇古怪的状态,需要不止一个变量来表示.这种情况下如果需要使用DP 就必须把状态压缩成一个数来表示,并且一个数只能对应于一种状态. 特别地,对于集合我们可以把每一个元素的选取与否对应到一个二进制位里,从而把状态压缩成一个整数,大大方便了计算和维护. 对于不是整数的情况,很多时候很难确定一个合适的递推顺序,因此使用记忆化搜索可以避免这个问题.如下面TSP问题的法一. TSP问题 一张图上有n个点,给定相应的邻接矩阵,需要求出

Gym - 101915D Largest Group 最大独立集 Or 状态压缩DP

题面题意:给你N个男生,N个女生,男生与男生之间都是朋友,女生之间也是,再给你m个关系,告诉你哪些男女是朋友,最后问你最多选几个人出来,大家互相是朋友. N最多为20 题解:很显然就像二分图了,男生一边女生一边的,然后一种解法就是 求图的最大独立集,(看起来很巧,实则也是一种套路) (最大独立集是一个点集,其中任意两点在图中无对应边,对于一般图来说,最大独立集是一个NP完全问题,对于二分图来说最大独立集=|V|-二分图的最大匹配数) 我们本来连边是,所有的朋友关系连边(男女就行了,同性都可以忽略

POJ 3254 Corn Fields 状态压缩DP (C++/Java)

http://poj.org/problem?id=3254 题目大意: 一个农民有n行m列的地方,每个格子用1代表可以种草地,而0不可以.放牛只能在有草地的,但是相邻的草地不能同时放牛, 问总共有多少种方法. 思路: 状态压缩的DP. 可以用二进制数字来表示放牧情况并判断该状态是否满足条件. 这题的限制条件有两个: 1.草地限制. 2.相邻限制. 对于草地限制,因为输入的时候1是可以种草地的. 以"11110"草地分析,就只有最后一个是不可以种草的.取反后得00001  .(为啥取反

HDU1565(状态压缩dp)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8170    Accepted Submission(s): 3095 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数

HDU 3001【状态压缩DP】

题意: 给n个点m条无向边. 要求每个点最多走两次,要访问所有的点给出要求路线中边的权值总和最小. 思路: 三进制状态压缩DP,0代表走了0次,1,2类推. 第一次弄三进制状态压缩DP,感觉重点是对数据的预处理,利用数组分解各个位数,从而达到类似二进制的目的. 然后就是状态的表示,dp[s][i]表示状态s时到达i的最优值. 状态转移也一目了然,不废话. #include<stdio.h> #include<string.h> #include<algorithm> u

Victor and World(spfa+状态压缩dp)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5418 Victor and World Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Others)Total Submission(s): 958    Accepted Submission(s): 431 Problem Description After trying hard fo