poj2288

題目大意:求一條哈密頓迴路,但是權值計算不同,包括三部分:1.經過的所有點的權值相加。2.經過的連續兩個點的權值的乘積。3.能夠構成三角型的連續三個點的乘積。這些全部加起來就是這條迴路的總權值。輸出最大權值和這個最大權值的路線有多少條


解題思路:先處理好兩相連的情況,如果i與j,我們很容易得到dp[i][j][s]=(v[i]+v[j]+v[i]*v[j]);這相當於dp的初始化,i與j表                   示相連的兩點,s表示當前走過的狀態,接下來就是處理三點之間的關係了,當i與j滿足相連關係時,枚舉第                   三個點的所有情況,當他滿足與j相連是,增加量ans=v[k]*v[j]+v[k], 若果k還滿足了與i相連,那麼         ans=ans+v[i]*v[j]*v[k];由於此題還要記錄這樣的路線數量,因此我們還需要一的三維數組記錄到達各個路線的條數

當滿足相等的情況是,num數組就應該相加進行更新,當新的路線權值大於舊的路線是,我們只需覆蓋跟新,(想想爲什麼)(注意轉移時的各種滿足條件,不要漏寫!!!)


代碼:

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL __int64
LL dp[15][15][1<<13],num[15][15][1<<13];
int map[13][13],a1[15],v[15];
int main()
{
    int T,n,m;
    scanf("%d",&T);
    while(T--)
    {
        int i,j,k,s,a,b;
        memset(map,0,sizeof(map));
        memset(num,0,sizeof(num));
        memset(dp,0,sizeof(dp));
        scanf("%d%d",&n,&m);
        for(i=0;i<n;i++)
        {
            scanf("%d",&v[i]);
        }
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            a--,b--;
            map[a][b]=map[b][a]=1;
        }
        a1[0]=1;
        for(i=1;i<=13;i++)
        {
            a1[i]=a1[i-1]*2;
        }
        if(n==1)//只有一個點時,直接輸出第一個點的點權
        {
            printf("%d 1\n",v[0]);
        }
        else
        {
            for(i=0;i<n;i++)
            {
                for(j=0;j<n;j++)
                {
                    if(map[i][j]==0||i==j)continue;
                    int s=(a1[i]|a1[j]);
                    dp[i][j][s]=(v[i]+v[j]+v[i]*v[j]);
                    num[i][j][s]=1;//記錄滿足條件的路徑有幾條
                }
            }
            for(s=0;s<a1[n];s++)
            {
                for(i=0;i<n;i++)
                {
                    if((s&a1[i])==0)continue;
                    for(j=0;j<n;j++)
                    {
                        if(i==j||(s&a1[j])==0||dp[i][j][s]==0)continue;
                        if(map[i][j]==0)continue;
                        for(k=0;k<n;k++)
                        {
                            if(i==k||j==k||(s&a1[k])!=0||map[k][i]==0)continue;
                            int t=s|a1[k];
                            LL ans1=v[i]*v[k]+v[k];//k與i相連
                            if(map[k][j]!=0)//k與j相連滿足,那麼i,j,k三點兩兩相連
                            {
                                ans1+=v[i]*v[j]*v[k];
                            }
                            if(dp[k][i][t]<dp[i][j][s]+ans1)
                            {
                                dp[k][i][t]=dp[i][j][s]+ans1;
                                num[k][i][t]=num[i][j][s];
                            }
                            else if(dp[k][i][t]==dp[i][j][s]+ans1)
                            {
                                dp[k][i][t]=dp[i][j][s]+ans1;
                                num[k][i][t]+=num[i][j][s];
                            }
                        }
                    }
                }
            }
            LL ans=0,tol=0;
            for(i=0;i<n;i++)
            {
                for(j=0;j<n;j++)
                {
                    if(ans<dp[i][j][a1[n]-1])
                    {
                        ans=dp[i][j][a1[n]-1];
                        tol=num[i][j][a1[n]-1];
                    }
                    else if(ans==dp[i][j][a1[n]-1])
                    {
                        ans=dp[i][j][a1[n]-1];
                        tol+=num[i][j][a1[n]-1];
                    }
                }
            }
            printf("%I64d %I64d\n",ans,tol/2);//除以2的原因是因爲無向圖,而i到j,j到i我們各算了一次
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章