1. 程式人生 > >bzoj 3055 禮物運送

bzoj 3055 禮物運送

首先處理出兩點之間最短路,設狀態f[i][j]表示j狀態下結尾為i的最短路,所以有轉移f[i][j]=f[k][j|(1<<(k-1))]+dis[i][k];

初狀態就是f[i][(1<<(i-1))]=dis[1][i],因為忽略了第一個點,在列舉的時候後面的點都要為i-2,具體看程式碼。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int n,m;
int head[20],cnt=1;
int used[20][20],dis[20][20];
int f[20][(1<<18)+5],dp[(1<<18)+5],tot=0x3f3f3f3f;
struct node
{
	int to,nxt,val;
}edge[200005];
struct wee
{
	int val,pos;
}xz[20][20];
void init()
{
	memset(head,-1,sizeof(head));
	memset(dis,0x3f,sizeof(dis));
	memset(dp,0x3f,sizeof(dp));
}
void add(int from,int to,int val)
{
	edge[cnt].to=to;
	edge[cnt].val=val;
	edge[cnt].nxt=head[from];
	head[from]=cnt++;
}
int cmp(wee x,wee y)
{
	return x.val<y.val;
}
queue<int>M;
void spfa(int rt)
{
	dis[rt][rt]=0;
	used[rt][rt]=1;
	M.push(rt);
	while(!M.empty())
	{
		int u=M.front();M.pop();
		for(int i=head[u];i!=-1;i=edge[i].nxt)
		{
			int to=edge[i].to;
			if(dis[rt][to]>dis[rt][u]+edge[i].val)
			{
				dis[rt][to]=dis[rt][u]+edge[i].val;
				if(used[rt][to])continue;
				M.push(to);used[rt][to]=1;
			}
		}
		used[rt][u]=0;
	}
}
int main()
{
	scanf("%d%d",&n,&m);init();
	for(int i=1;i<=m;i++)
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c);add(b,a,c);
	}
	for(int i=1;i<=n;i++)spfa(i);
	memset(f,0x3f,sizeof(f));
	for(int i=2;i<=n;i++)
	{
		f[i][(1<<(i-2))]=dis[1][i];
	}
	for(int j=0;j<=(1<<(n-1))-1;j++)
	{
		for(int i=2;i<=n;i++)
		{
			if(j&(1<<(i-2)))
			{
				for(int k=2;k<=n;k++)
				{
					if(!(j&(1<<(k-2))))
					{
						f[k][j|(1<<(k-2))]=min(f[k][j|(1<<(k-2))],f[i][j]+dis[i][k]);
					}
				}
			}
		}
	}
	for(int i=0;i<=(1<<(n-1))-1;i++)
	{
		for(int j=2;j<=n;j++)
		{
			dp[i]=min(dp[i],f[j][i]);
		}
	}
	for(int i=0;i<=(1<<(n-1))-1;i++)
	{
		tot=min(tot,max(dp[i],dp[(1<<(n-1))-1-i]));
	}
	printf("%d",tot);
	return 0;
}