POJ2288Islands and Bridges(状态压缩DP,求最大路和走条数)

Islands and Bridges

Time Limit: 4000MS   Memory Limit: 65536K
Total Submissions: 8845   Accepted: 2296

Description

Given a map of islands and bridges that connect these islands, a Hamilton path, as we all know, is a path along the bridges such that it visits each island exactly once. On our map, there is also a positive integer value associated with each island. We call
a Hamilton path the best triangular Hamilton path if it maximizes the value described below.

Suppose there are n islands. The value of a Hamilton path C1C2...Cn is calculated as the sum of three parts. Let Vi be the value for the island Ci. As the first part, we sum over all the Vi values for each island in the path. For the second part, for each edge
CiCi+1 in the path, we add the product Vi*Vi+1. And for the third part, whenever three consecutive islands CiCi+1Ci+2 in the path forms a triangle in the map, i.e. there is a bridge between Ci and Ci+2,
we add the product Vi*Vi+1*Vi+2.

Most likely but not necessarily, the best triangular Hamilton path you are going to find contains many triangles. It is quite possible that there might be more than one best triangular Hamilton paths; your second task is to find the number of such paths.

Input

The input file starts with a number q (q<=20) on the first line, which is the number of test cases. Each test case starts with a line with two integers n and m, which are the number of islands and the number of bridges in the map, respectively. The next line
contains n positive integers, the i-th number being the Vi value of island i. Each value is no more than 100. The following m lines are in the form x y, which indicates there is a (two way) bridge between island x and island y. Islands are numbered from 1
to n. You may assume there will be no more than 13 islands.

Output

For each test case, output a line with two numbers, separated by a space. The first number is the maximum value of a best triangular Hamilton path; the second number should be the number of different best triangular Hamilton paths. If the test case does not
contain a Hamilton path, the output must be `0 0‘.

Note: A path may be written down in the reversed order. We still think it is the same path.

Sample Input

2
3 3
2 2 2
1 2
2 3
3 1
4 6
1 2 3 4
1 2
1 3
1 4
2 3
2 4
3 4

Sample Output

22 3
69 1

Source

Shanghai 2004

题意:有n个点,每个点都有一个价值,无论从哪个点走,要求每个点只能走一次,求出怎么走使得到的价值最大,且求出最大价值的路有多少条。假设有4个点,它的最大走法是1-->4-->2-->3,且1,4,2三点可以形成三角形,4,2,3也可以形成三角形,那么最大价值为:v[1]+v[4]+v[2]+v[3]+v[1]*v[4]+v[4]*v[2]+v[1]*v[4]*v[2]+v[2]*v[3]+v[4]*v[2]*v[3]。

解题:dp[state][i][j]表示状态state以j点结尾且j点的前一个点是i。具体的看代码。

#include<stdio.h>
#include<string.h>
#define FOR(i,l,r) for(i=l;i<=r;i++)
#define mulit(j) (1<<j)
typedef struct nnn
{
    __int64 sum,k;
}node;
node dp[mulit(13)+5][14][14];
int map[14][14];
__int64 v[14];

int main()
{
    int t,n,m,a,b,i,j;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        FOR(i,0,mulit(n)-1)//初始化
        FOR(j,0,n-1)
        for(int e=0;e<n;e++)
            dp[i][j][e].sum=-1;
        memset(map,0,sizeof(map));

        FOR(i,0,n-1)
            scanf("%I64d",&v[i]);
        while(m--)
        {
            scanf("%d%d",&a,&b); a--,b--;
            map[a][b]=map[b][a]=1;
        }
        if(n==1)
        {
            printf("%I64d %d\n",v[0],1); continue;
        }
        for( i=0;i<n;i++)//处理两个点的状态
        for( j=i+1;j<n;j++)
        if(map[i][j])
        {
            int state=mulit(i)+mulit(j);
            dp[state][i][j].sum=dp[state][j][i].sum=v[i]+v[j]+v[i]*v[j];
            dp[state][i][j].k=dp[state][j][i].k=1;
        }
        for(int state=1;state<mulit(n);state++)//枚举状态,处理两个点以上
        for( j=0;mulit(j)<=state;j++)//状态以j点结尾
        if(state&mulit(j))
        for( i=0;mulit(i)<=state;i++)//状态结尾点j的前一个点i,从i--->j.
        if(i!=j&&(mulit(i)&state))
        {
            if(dp[state][i][j].sum==-1)continue;//没有该状态是从i--->j,以j为结尾点的状态
            for(int e=0; e<n; e++)//找到一个点e,存在从j--->e,e没有走过,不在该状态
            if((mulit(e)&state)==0&&map[j][e])
            {
                int tstat=state+mulit(e),ss=0;
                if(map[i][e])//状态tstat以i,j,e三点结尾的可以形成三角形
                   ss=v[i]*v[j]*v[e];

                if(dp[tstat][j][e].sum<dp[state][i][j].sum+v[e]+v[j]*v[e]+ss)//更新
                    {
                        dp[tstat][j][e].sum=dp[state][i][j].sum+v[e]+v[j]*v[e]+ss;
                        dp[tstat][j][e].k=dp[state][i][j].k;
                    }
                else if(dp[tstat][j][e].sum==dp[state][i][j].sum+v[e]+v[j]*v[e]+ss)
                        dp[tstat][j][e].k+=dp[state][i][j].k;
            }
        }
        __int64 maxsum=-1,k=0;
        for(i=0; i<n;i++)
        for(j=0;j<n;j++)
        if(i!=j&&dp[mulit(n)-1][i][j].sum!=-1)
        {
            if(dp[mulit(n)-1][i][j].sum>maxsum)
            {
                maxsum=dp[mulit(n)-1][i][j].sum;
                k=dp[mulit(n)-1][i][j].k;
            }
            else if(dp[mulit(n)-1][i][j].sum==maxsum)
                k+=dp[mulit(n)-1][i][j].k;
        }
        if(maxsum==-1)maxsum=0;//没有把所有的点只走一次就能全部点都走到
        printf("%I64d %I64d\n",maxsum,k/2);
        /* k/2是因为:假设有4个点,最大走法是3-->1-->4-->2,那么2-->4-->1-->3也是最大走法,
                      但走法都是算一条走法,因为路的条数和走的方向没有关系。
        */
    }
}

POJ2288Islands and Bridges(状态压缩DP,求最大路和走条数)

时间: 2024-08-22 13:32:29

POJ2288Islands and Bridges(状态压缩DP,求最大路和走条数)的相关文章

zoj3010The Lamp Game(状态压缩+SPFA求最大路)经典

The Lamp Game Time Limit: 2 Seconds Memory Limit: 65536 KB Little Tom likes playing games. Recently he is fond of a game called Lamp Game. The game is like this: at first, there are n lamps on the desk, all of which are lighted and Tom is given an in

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 <

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个格子不能相邻,并且取出的数

POJ 3311 【状态压缩DP】

题意: 给n个点,给出矩阵代表i到j单向边的距离. 要求,不介意访问每个点的次数,要求访问完每个点,使得路程总和最小. 思路: 由于不介意访问每个点的次数,所以可以先进行FLOYD求出任意两个点之间的最短路,然后就是DP. 同样的,1代表有访问过,0代表没访问过. dp[s][j]代表访问状态为s的情况下最终到达点j的最优值. 枚举状态s中每一个可以到达的点,从所有可能的点中枚举对其进行更新. 关于状态压缩的细节方面,注意从左边数第i位是从0开始数的,所以第i位代表第i+1个点. 然后状态的总数

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

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

HDU--1074(状态压缩DP)

典型的状态压缩DP,给出了每件作业的截止时间和花费,求让老师扣分最少的写作业方式.把完成n种作业用状态2^n-1表示,dp[s]表示 完成状态s时,最小扣分.比如“111”,那么可以由“011”,“110”,“101”转移过来,分别表示选了0,1号作业,1,2号作业,0,2号作业. t[s]表示状态S记录的总时间.dp[s] = min{dp[j]+c[k] - d[k]},其中j = i^(1<<k),0<k<n;pre[s]表示状态s完成时,最末尾完成的作业, #include

1252 - Twenty Questions(状态压缩DP)

经典的状态压缩DP .  有没有感觉这道题和什么东西有点像?  没错,是01背包 . 将特征看作物品 , 只不过这里的状态有点复杂, 需要用一个集合才能表示它, 所以我们用d[s][a]来表示,已经询问了特征集s , 假设我们要猜的物品是w ,w所具备的特征集为a ,此时还要询问的最小次数 .   显然a是s的子集,而且要注意本题的要求, 求的是最小化的最大询问次数 .也就是说无论猜哪个物品,猜这么多次一定能猜到 . 那么状态如何转移呢? 就像背包问题,对于一个特征k ,我们要抉择:要k还是不要