POJ 2288 Islands and Bridges(状压dp)

来源:互联网 发布:认字卡片软件 编辑:程序博客网 时间:2024/05/16 15:14

思路:所求的哈密顿路径由三部分组成,一,所有节点的权值之和,二,每条边的权值之和,三,三元环的权值和。设集合S为拜访的点的集合,当向集合S中加入一个点,与上一条边的起点和终点有关。所以令dp[s][i][j]表示集合S通过边(i, j)加入j点之后的最大权值。

那么 dp[s][i][j] = max(dp[s][i][j], dp[p][k][i] + tmp). p表示未加入j点的集合,tmp表示加入j点之后增加的权值,tmp = v[j] + v[i] * v[j], 如果i, j, k三点构成三元环,那么tmp再加上v[i] * v[j] * v[k].

再用一个数组统计路径数。

注意答案会超过int,要用long long.

具体细节见代码

#include<cstdio>#include<set>#include<algorithm>#include<cstring>#include<iostream>#include<map>#include<queue>#include<vector>#include<stack>#include<string>#include<sstream>#include<set>#include<cmath>using namespace std;const int INF = 0x3f3f3f3f;const int maxn = 1e2 + 20;const double EPS = 1e-8;const int mod = 1e8;typedef unsigned long long ull;typedef long long LL;int dx[] = {0, 0, -1, 1, -1, -1, 1, 1};int dy[] = {1, -1, 0, 0, -1, 1, -1, 1};inline int dcmp(double x, double y){if(fabs(x - y) < EPS) return 0; return x > y ? 1 : -1; }int n, m;int g[13][13];LL dp[1 << 13][13][13];int num[1 << 13][13][13];int v[13];int main(){    int T;    scanf("%d", &T);    while(T--){        scanf("%d%d", &n, &m);        for(int i = 0; i < n; ++i){            scanf("%d", &v[i]);        }        memset(g, 0, sizeof g);        memset(num, 0, sizeof num);        for(int i = 0; i < m; ++i){            int x, y;            scanf("%d%d", &x, &y);            g[x - 1][y - 1] =  g[y - 1][x - 1] = 1;        }        memset(dp, -1, sizeof dp);        for(int i = 0; i < n; ++i){            for(int j = 0; j < n; ++j){                if(i == j) continue;                if(g[i][j] == 0) continue;                dp[1 << i | (1 << j)][i][j] = v[i] + v[j] + v[i] * v[j];                num[1 << i | (1 << j)][i][j] = 1;            }        }        LL ans = -1;        for(int i = 0; i < (1 << n); ++i){            for(int j = 0; j < n; ++j){                if(i & (1 << j)) continue;                for(int k = 0; k < n; ++k){                    if(j == k) continue;                    if(!(i & (1 << k)))continue;                    if(g[k][j] == 0) continue;                    for(int l = 0; l < n; ++l){                        if(k == l)continue;                        if(l == j) continue;                        if(!(i & (1 << l)))continue;                        if(dp[i][l][k] == -1)continue;                        LL s = v[j] + v[k] * v[j] + dp[i][l][k];                        if(g[j][l]) s += v[k] * v[j] * v[l];                        if(dp[i | (1 << j)][k][j] < s){                            dp[i | (1 << j)][k][j] = s;                            num[i | (1 << j)][k][j] = num[i][l][k];                        }                        else if(dp[i | (1 << j)][k][j] == s){                            num[i | (1 << j)][k][j] += num[i][l][k];                        }                    }                }            }        }        LL cnt = 0;        int t = (1 << n) - 1;        for(int j = 0; j < n; ++j){            for(int k = 0; k < n; ++k){                if(j == k) continue;                ans = max(ans, dp[t][j][k]);            }        }        for(int j = 0; j < n; ++j){            for(int k = 0; k < n; ++k){                if(j == k) continue;                if(dp[t][j][k] == ans) cnt += num[t][j][k];            }        }        cnt /= 2;        if(n == 1) ans = v[0], cnt = 1;        if(ans != -1)        printf("%lld %lld\n", ans, cnt);        else            printf("0 0\n");    }}/**/


原创粉丝点击