版权声明: https://blog.csdn.net/moon_sky1999/article/details/85240740
题目来源:http://poj.org/problem?id=2288
状压dp。f[i][j][k]表示状态为i时,上一条边为(j,k),这样记录了路径上之前两个结点的信息,就能进行修改。
注意特判n==1的情况,最终结果应该/2。
转移的过程中记录满足要求的路径数,当且仅当当前状态可以到达时再用其进行状态转移。
代码:
import java.io.*;
import java.lang.*;
import java.rmi.*;
import java.util.*;
import java.math.*;
public class Main {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
static double nextDouble() throws IOException {
in.nextToken();
return in.nval;
}
static long nextLong() throws IOException {
in.nextToken();
return (long) in.nval;
}
static String next() throws IOException {
in.nextToken();
return in.sval;
}
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static int n, m;
static long v[];
static boolean g[][];
static long f[][][];
static long t[][][];
static final long inf = 1000000010;
static long Min(long a, long b) {
return a < b ? a : b;
}
public static void main(String[] args) throws IOException {
v = new long[15];
g = new boolean[15][15];
f = new long[(1 << 13)][14][14];
t = new long[(1 << 13)][14][14];
int T;
T = nextInt();
while (T-- != 0) {
n = nextInt();
m = nextInt();
for (int i = 1; i < (1 << n); ++i) {
for (int j = 1; j <= n; ++j) {
for (int k = 1; k <= n; ++k) {
f[i][j][k] = t[i][j][k] = 0;
}
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
g[i][j] = false;
}
}
for (int i = 1; i <= n; ++i) {
v[i] = nextLong();
}
for (int i = 1; i <= m; ++i) {
int x, y;
x = nextInt();
y = nextInt();
g[x][y] = g[y][x] = true;
}
if (n == 1) {
out.print(v[1]);
out.print(' ');
out.println(1);
continue;
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (i != j && g[i][j]) {
f[(1 << (i - 1) | (1 << (j - 1)))][i][j] = f[(1 << (i - 1) | (1 << (j - 1)))][j][i] = v[i] + v[j] + v[i] * v[j];
t[(1 << (i - 1) | (1 << (j - 1)))][i][j] = t[(1 << (i - 1) | (1 << (j - 1)))][j][i] = 1;
}
}
}
for (int i = 1; i < (1 << n); ++i) {
for (int j = 1; j <= n; ++j)
if (((1 << (j - 1)) & i) != 0) {
for (int k = 1; k <= n; ++k)
if (k != j && ((1 << (k - 1)) & i) != 0 && g[j][k] && t[i][j][k] > 0) {
for (int p = 1; p <= n; ++p) {
if (((1 << (p - 1)) & i) == 0 && g[k][p]) {
long c = v[p] + v[k] * v[p];
if (g[j][p]) c += v[j] * v[k] * v[p];
if (f[i | (1 << (p - 1))][k][p] < f[i][j][k] + c) {
f[i | (1 << (p - 1))][k][p] = f[i][j][k] + c;
t[i | (1 << (p - 1))][k][p] = t[i][j][k];
} else if (f[i | (1 << (p - 1))][k][p] == f[i][j][k] + c) {
t[i | (1 << (p - 1))][k][p] += t[i][j][k];
}
}
}
}
}
}
long ans = 0;
long tot = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j)
if (i != j && g[i][j]) {
if (ans < f[(1 << n) - 1][i][j] && t[(1 << n) - 1][i][j] != 0) {
ans = f[(1 << n) - 1][i][j];
tot = t[(1 << n) - 1][i][j];
} else if (ans == f[(1 << n) - 1][i][j]) {
tot += t[(1 << n) - 1][i][j];
}
}
}
if (tot == 0) {
out.println("0 0");
} else {
out.print(ans);
out.print(' ');
out.println(tot / 2);
}
}
out.flush();
}
}