【动态规划】[POJ 2288]Islands and Bridges

这倒题太坑了。。。简直。。。明明没有错误的代码就是A不了。。
题目分析另f(state,i,j) 表示在状态为state的情况下当前在i点前一个点是j点的所能够得到的最大的乘积那么很容易发现

f(state+(1<<k),k,i)=f(state,i,j)+v[k]+v[k]×v[i]|G[j][k]=0
或者
f(state+(1<<k),k,i)=f(state,i,j)+v[k]+v[k]×v[i]+v[k]×v[i]×v[j]|G[j][k]=1
其中G表示i,j是否连通,那么最终的答案就是
max{f((1<<n)1,i,j)}
这里i和j是需要枚举的,然后怎么寻找方案数量呢定义 g(state,i,j)表示在状态为state的情况下当前在i点前一个点是j点的所能够得到的最大的乘积的方案数量那么
g(state+(1<<k),k,i)=g(state,i,j)|f(state+(1<<k),k,i)<f(state,i,j)+v[k]+v[k]×v[i]

在相等条件的情况下的时候
g(state+(1<<k),k,i)+=g(state,i,j)
剩下的就是注意代码了,如果一直Ac不了,删了重新写吧。。。
#include <cstdio>
#include <cstring>
using namespace std;
/*********/
typedef long long LL;
const int MAXN = 13;

int Map[MAXN+2][MAXN+2];
LL way[int(1<<MAXN)+2][MAXN+2][MAXN+2];
LL dp[int(1<<MAXN)+2][MAXN+2][MAXN+2];
LL v[MAXN+2], n, m;
/*********/
void DP(){
    memset(dp, -1, sizeof dp);
    memset(way, 0, sizeof way);
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(i==j) continue;
            if(!Map[i][j]) continue;
            dp[(1<<i)+(1<<j)][i][j] = v[i] * v[j] + v[i] + v[j];
            way[(1<<i)+(1<<j)][i][j] = 1;
        }
    }
    int Max = 1 << n;
    for(int state=0; state<Max; state++){
        for(int i=0; i<n; i++){
            if((state & (1 << i)) == 0) continue;
            for(int j=0; j<n; j++){
                if((state & (1 << j)) == 0) continue;
                if(i == j) continue;
                if(!Map[i][j]) continue;
                if(dp[state][j][i] == -1) continue;
                for(int k=0; k<n; k++){
                    if(k == i || k == j) continue;
                    if(!Map[j][k]) continue;
                    if((state & (1 << k)) != 0) continue;
                    int _state = state + (1 << k);
                    int tmp = dp[state][j][i] + v[k] + v[k] * v[j];
                    if(Map[i][k]) tmp += v[k] * v[j] * v[i];
                    if(tmp > dp[_state][k][j]){
                        dp[_state][k][j] = tmp;
                        way[_state][k][j] = way[state][j][i];
                    }else if(tmp == dp[_state][k][j])
                        way[_state][k][j] += way[state][j][i];
                }
            }
        }
    }
    long long ans=-1, wsum=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(i == j || !Map[i][j]) continue;
            if(dp[Max-1][i][j] > ans){
                ans = dp[Max-1][i][j];
                wsum = way[Max-1][i][j];
            }else if(dp[Max-1][i][j] == ans)
                wsum += way[Max-1][i][j];
        }
    }
    printf("%I64d %I64d\n", ans==-1?0:ans, wsum/2);
}
int main(){
    int T, u, vp;
    scanf("%d", &T);
    while(T--){
        memset(Map,  0, sizeof Map);
        scanf("%I64d%I64d", &n, &m);
        for(int i=0; i<n; i++) scanf("%I64d", &v[i]);
        for(int i=0; i<m; i++){
            scanf("%d%d", &u, &vp);
            u --; vp --;
            Map[u][vp] = Map[vp][u] = 1;
        }
        if(n == 1) printf("%I64d 1\n", v[0]);
        else DP();
    }

    return 0;
}

转载于:https://www.cnblogs.com/JeremyGJY/p/5921702.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值