1. 程式人生 > >POJ 2288 Islands And Bridges 狀態壓縮dp+哈密頓回路

POJ 2288 Islands And Bridges 狀態壓縮dp+哈密頓回路

pac -1 path max def %d 註意 sca can

題意:n個點 m條邊的圖,路徑價值定義為相鄰點乘積,若路路徑c[i-1]c[i]c[i+1]中c[i-1]-c[i+1]有邊 則價值加上三點乘積
找到價值最大的哈密頓回路,和相應的方法數n<=13.
暴力dfs O(13!) TLE

由於n<13 經典的狀態壓縮dp [狀態] [當前點位置 ][前一點位置] 註意上一個狀態必須合法才能進行轉移
設狀態dp[s][i][j] 當前狀態為s,當前點為i上一個點為j的最大價值, ans=max(dp[(1<<n)-1][i])
dp[s][i][j]= S=s^(1<<(i-1))&&dp[S][j][k]狀態合法 max(dp[S][j][k]+v[j]*v[k]+v[i]*v[j]*v[k] (c[k],c[i]存在邊))
O(2^13*13^3)

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N=1<<14;
ll n,m,v[15],g[15][15];
ll dp[N][15][15],path[N][15][15];
int main()
{
	int q;
	scanf("%d",&q);
	while(q--)
	{
		memset(dp,-1,sizeof(dp));
		memset(g,0,sizeof(g));
		memset(path,0,sizeof(path));
		scanf("%I64d%I64d",&n,&m);
		for(int i=0;i<n;i++)
			scanf("%I64d",&v[i]);
		int u,V;
		while(m--)
		{
			scanf("%d%d",&u,&V);
			u--,V--;
			g[u][V]=g[V][u]=1;
		}
		if(n==1)
		{
			cout<<v[0]<<‘ ‘<<1<<endl;
			continue;
		}
		//3?ê??ˉ?àáúá?μ??·??dp?μ 
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<n;j++)
			{
				if(i==j)	continue;
				if(g[i][j])
				{
					dp[(1<<i)+(1<<j)][i][j]=v[i]+v[j]+v[i]*v[j];
					path[(1<<i)+(1<<j)][i][j]=1;
				}
			}
		}
		for(int s=0;s<(1<<n);s++)
		{
			for(int i=0;i<n;i++)
			{
				if(s&(1<<i)==0)	continue;
				for(int j=0;j<n;j++)
				{
					if(j==i||g[i][j]==0)	continue;
					if((s&(1<<j))==0)	continue;
					for(int k=0;k<n;k++)
					{
						if(j==k||((s&(1<<k))==0)||g[j][k]==0)	continue;
						int add=v[i]+v[i]*v[j];
						if(g[i][k])
							add+=v[i]*v[j]*v[k];
						int S=s^(1<<i);
						if(dp[S][j][k]==-1)	continue;//?°ò???×′ì?òao?·¨ 
						
						int tmp=dp[S][j][k]+add;
						if(tmp>dp[s][i][j])
							dp[s][i][j]=tmp,path[s][i][j]=path[S][j][k];
						else if(tmp==dp[s][i][j])
							path[s][i][j]+=path[S][j][k];
					}
				}
			}
		}
		ll ans=-1,cnt=0;
		ll s=(1<<n)-1;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<n;j++)
			{
				if(i==j)	continue;
				if(ans<dp[s][i][j])
					ans=dp[s][i][j],cnt=path[s][i][j];
				else if(ans==dp[s][i][j])
					cnt+=path[s][i][j];
			}	
		}	
		if(ans==-1)
			ans=0,cnt=0;	
		cout<<ans<<‘ ‘<<cnt/2<<endl;
	}
	return 0;
}

  

POJ 2288 Islands And Bridges 狀態壓縮dp+哈密頓回路