牛客练习赛17 E 求长度(状压+bfs预处理)

题意:给你一个图,并告诉你只能走那些点,问你从0走完这S个点在回去的最短路是多少

思路:首先预处理出从这S+1个点(0和S个点)两两到达的距离,之后就是一发裸的状压就好了

上代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000+10;
const int INF = 9999999;
struct node
{
	int to,nex,val;
}edg[maxn<<1];
int n,m,cnt;
int head[maxn],dis[maxn],vis[maxn];
int DIS[12][12];
int rode[maxn],dp[1<<11][11];
void init()
{
	cnt = 0 ;
	memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)
{
	edg[cnt].to = v;
	edg[cnt].val = w;
	edg[cnt].nex = head[u];
	head[u] = cnt++;
}
int SPFA(int s,int e)
{
	for(int i = 0 ; i < n ; i++)
	{
		dis[i] = INF;
		vis[i] = 0;
	}
	queue<int>que;
	while(!que.empty()) que.pop();
	que.push(s);
	dis[s] = 0;
	while(!que.empty())
	{
		int u = que.front();
		que.pop();
		vis[u] = 0;
		for(int i = head[u] ; i != -1 ; i = edg[i].nex)
		{
			int v = edg[i].to;
			int w = edg[i].val;
			if(dis[v] > dis[u] + w)
			{
				dis[v] = dis[u] + w;
				if(!vis[v]){
					vis[v] = 1;
					que.push(v);
				} 
			}
		}
	}
	return dis[e];
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		
		scanf("%d%d",&n,&m);
		memset(DIS,0,sizeof(DIS));
		init();
		int a,b,c;
		for(int i = 0 ; i < m ; i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			add(a,b,c);
			add(b,a,c);
		}
		for(int i = 0 ; i < n ; i++)
		{
			for(int j = head[i] ; j!= -1 ; j = edg[j].nex)
			{
				int v = edg[j].to;
				int w = edg[j].val;
			}
		}
		int te;
		scanf("%d",&te);
		for(int i = 1 ; i <= te ; i ++)
		{
			scanf("%d",&rode[i]);
		}
		for(int i = 1 ; i <= te ; i++)
		{
			DIS[0][i] = DIS[i][0] = SPFA(0,rode[i]);
		}
		for(int i = 1 ; i <= te ; i ++)
		{
			for(int j = i + 1 ; j <= te ; j++)
			{
				DIS[i][j] = DIS[j][i] = SPFA(rode[i],rode[j]);
			}
		}
	/*	for(int i = 0 ; i <= te ; i++)
		{
			for(int j = 0 ; j <= te ; j ++)
			{
				printf("%d ",DIS[i][j]);
			}
			puts("");
		}*/
		te++;
		for(int i = 0 ; i < (1<<te) ; i++)
		{
			for(int j = 0 ; j < te ; j ++) dp[i][j] = INF;
		}
		dp[0][0] = 0;
		for(int state = 0 ; state < (1<<te) ; state++)
		{
			for(int i = 0 ; i < te ; i ++)
			{
				if(dp[state][i] == INF) continue;
				for(int j = 0 ; j < te ; j++)
				{
					if((1<<j)&state) continue;
					if(DIS[i][j] == INF) continue;
					dp[(1<<j)|state][j] = min(dp[(1<<j)|state][j] , dp[state][i] + DIS[i][j]);
				}
			}
		}
		int ans = INF;
		for(int i = 0 ;i < te ; i++)
		{
		//	printf("%d %d\n",dp[(1<<te)-1][i] , DIS[i][0]);
			ans = min(ans,dp[(1<<te)-1][i] + DIS[i][0]);
		}
		printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wjmwsgj/article/details/80240873