poj 2280 Islands and Bridges 哈密尔顿路 状压dp

题目链接

题意

给定一个\(N\)个点的无向图,求一条哈密尔顿路径\(C_1C_2...C_n\),使其\(value\)最大。

\(value\)的计算方式如下:$$\begin{aligned}value&=\sum_{i=1}{n}C_i\&+\sum_{i=1}C_iC_{i+1}\&+\sum_{i=1}^{n-2}C_iC_{i+1}*C_{i+2}[(C_i,C_{i+2})is\ an\ edge\ in\ the\ graph]\end{aligned}$$

思路

状态表示及转移等与前两题相类似。

因为状态和前两步相关,所以用\(dp[state][i][j]\)表示,接连经过\(j\)点与\(i\)点到达\(state\)状态的最大\(value\)值和对应的路径数目。

注意答案会爆\(int\).

Code

#include <cstdio>
#include <iostream>
#include <cstring>
#define maxn 10010
#define inf 0x3f3f3f3f
#define F(i, a, b) for (LL i = (a); i < (b); ++i)
#define F2(i, a, b) for (LL i = (a); i <= (b); ++i)
#define dF(i, a, b) for (LL i = (a); i > (b); --i)
#define dF2(i, a, b) for (LL i = (a); i >= (b); --i)
using namespace std;
bool vis[maxn][13][13], dis[13][13];
typedef long long LL;
LL v[13], n, m;
struct node { LL v, w, flag; }dp[maxn][13][13];
node dfs(LL state, LL p1, LL p2) {
    if (state==(1<<p1)+(1<<p2)) return {v[p1]+v[p2]+v[p1]*v[p2], 1, 1};
    if (vis[state][p1][p2]) return dp[state][p1][p2];
    vis[state][p1][p2] = true;
    LL sta = state - (1<<p1);
    node ans = {0, 0, 0};
    bool flag = false;
    F(i, 0, n) {
        if (i==p1 || i==p2 || !dis[i][p2] || !(state&(1<<i))) continue;
        node nd = dfs(sta, p2, i);
        if (!nd.flag) continue;
        flag = true;
        LL temp = nd.v + (dis[p1][i]?v[p1]*v[p2]*v[i]:0);
        if (temp > ans.v) ans = {temp, nd.w};
        else if (temp == ans.v) ans.w += nd.w;
    }
    if (!flag) return dp[state][p1][p2] = {0, 0, 0};
    else return dp[state][p1][p2] = {ans.v + v[p1] + v[p1]*v[p2], ans.w, 1};
}
void work() {
    memset(dis, 0, sizeof dis);
    memset(vis, 0, sizeof vis);
    memset(dp, 0, sizeof dp);
    scanf("%lld%lld", &n, &m);
    F(i, 0, n) scanf("%lld", &v[i]);
    F(i, 0, m) {
        LL u, v;
        scanf("%lld%lld", &u, &v); --u, --v;
        dis[u][v] = dis[v][u] = 1;
    }
    if (n==1) { printf("%lld %lld\n", v[0], 1); return; }
    node ans = {0, 0, 0};
    F(i, 0, n) {
        F(j, 0, n) {
            if (i==j || !dis[j][i]) continue;
            node temp = dfs((1<<n)-1, i, j);
            if (!temp.flag) continue;
            if (temp.v > ans.v) ans = temp;
            else if (temp.v == ans.v) ans.w += temp.w;
        }
    }
    printf("%lld %lld\n", ans.v, ans.w>>1);
}
int main() {
    LL T;
    scanf("%lld", &T);
    while (T--) work();
    return 0;
}

posted @ 2018-02-17 16:39  救命怀  阅读(143)  评论(0编辑  收藏  举报