Nine dynamic programming training

First of all can think of is like a template pressure dp

Take dp [state, i, j] represents the islands penultimate state is state i, the last one is the optimal solution when the island j,

num [state, i, j] for the corresponding number of paths, wherein State i-bit binary representation for i is 1 showing island visited, and 0 otherwise.
When it is clear that there are edges (i, j) exists, the initial value can be assigned the following:
** DP [(<<. 1 I) + (J <<. 1), I, J] = Val [I] Val + [ j] + val [i] * val [j], num [(1 << i) + (1 << j), i, j] = 1.
If the status
(state, i, j) up to check island k , if at this time k has not been accessed and have edges (J, k) : is present, the following operations
1) provided tmp when the next access island k the total benefits derived, r = State | (1 << k) .
2) If tmp> DP [R & lt, J, K] , represents a case can be updated to a more optimal solution, is updated:
DP [I, J, K] = tmp; **

num [r, j, k] = num [state, i, j].
3) If tmp == DP [R & lt, J, K] , can be obtained at this time indicates more ways to achieve local optimal solution, is updated:
NUM [R & lt, J, K] + = NUM [State, I, J ].

Similar to the shortest count

All final check the status ((n-<<. 1) -1, I, J) , can be superimposed on the optimal solution of the number of roads.
Note that, the subject agreed path of two kinds regarded as a kind of walking, so the final result to be divided by 2 .

code (written in a very clear, very clear, the equation looks very scary, is not difficult):
#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

int n,m;
int val[15],map[13][13];
int dp[1<<13][13][13];  //dp[state][i][j]表示state状态下倒数第二个岛为i,最后一个岛为j时的最优解
long long num[1<<13][13][13];   //num[state][i][j]为相应的路径数目

int main(){

    //freopen("input.txt","r",stdin);

    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
            scanf("%d",&val[i]);
        memset(map,0,sizeof(map));
        int u,v;
        while(m--){
            scanf("%d%d",&u,&v);
            u--;v--;
            map[u][v]=map[v][u]=1;
        }
        if(n==1){
            printf("%d 1\n",val[0]);
            continue;
        }
        memset(dp,-1,sizeof(dp));
        memset(num,0,sizeof(num));
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                if(i!=j && map[i][j]){
                    dp[(1<<i)|(1<<j)][i][j]=val[i]+val[j]+val[i]*val[j];
                    num[(1<<i)|(1<<j)][i][j]=1;
                }
        for(int i=0;i<(1<<n);i++)
            for(int j=0;j<n;j++)
                if((i&(1<<j))!=0)
                    for(int k=0;k<n;k++)
                        if(map[j][k] && j!=k && (i&(1<<k))!=0 && dp[i][j][k]!=-1)   
                            for(int x=0;x<n;x++)
                                if(map[k][x] && j!=x && k!=x && (i&(1<<x))==0){
                                    int tmp=dp[i][j][k]+val[x]+val[k]*val[x];
                                    if(map[j][x])
                                        tmp+=val[j]*val[k]*val[x];
                                    if(dp[i|(1<<x)][k][x]<tmp){
                                        dp[i|(1<<x)][k][x]=tmp;
                                        num[i|(1<<x)][k][x]=num[i][j][k];
                                    }else if(dp[i|(1<<x)][k][x]==tmp)
                                        num[i|(1<<x)][k][x]+=num[i][j][k];
                                }
        int ans1=0;
        long long ans2=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                if(i!=j && map[i][j]){
                    if(ans1<dp[(1<<n)-1][i][j]){
                        ans1=dp[(1<<n)-1][i][j];
                        ans2=num[(1<<n)-1][i][j];
                    }else if(ans1==dp[(1<<n)-1][i][j])
                        ans2+=num[(1<<n)-1][i][j];
                }
        cout<<ans1<<" "<<ans2/2<<endl;
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/wzxbeliever/p/11640826.html
Recommended