题目描述
TRT出国后,想找一个好的位置住下来。而他所在的城市,恰好有N栋建筑(从1~n编号),他会选择这些建筑的某一个居住。而建筑之间,有M条双向路相连。每条道路有一个起始点u,终止点v,以及走过这条道路所需的时间d。所有建筑都可以借助一些道路相互到达。TRT每天会从他的住房出发,按任意顺序拜访他的K个女神(他想怎么走就怎么走),不过由于TRT精力有限,他的女神个数不会超过12个。可他的女神们都比较娇气,希望TRT尽快来看她们(可她们却不会担心TRT的花心。。。)。对于第i个女神,她住在第p[i]栋建筑物,她每等x分钟(从TRT离家的那一时刻开始计算),她的焦急程度(初始为0)就会增加x。TRT当然希望她们高兴越好,而且他也不会让某个女神特别伤心,所以他希望所有女神的焦急程度的最大值越小越好。且他也不希望与任何一个女神住在一起,要不然会被众人黑成傻逼的(虽然他已经被我们黑成傻逼了)。所以他向你求助,帮他找出他应该住的那栋建筑,以及此时所有女神焦急程度最大值。
题解
观察到起点的选择并不会影响到之后在女神之间的路程。女神那么少当然是状压辣。所以可以先做女神的DP,先预处理出每个女神的最短路,考虑转移,只有一维已经拜访了谁似乎并不是很好转移,于是我们要发扬什么恶心就把什么放到维度上面去的做法,存一维表示最后拜访的是谁,这样就能转移了。家的答案只要 O ( n k ) O(nk) O(nk)扫一遍就可以了
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define maxn 10005
#define MAXN 50005
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
LL read(){
LL res=0,f=1; char c;
while(!isdigit(c=getchar())) if(c=='-') f=-1;
res=c^48;
while(isdigit(c=getchar())) res=(res<<1)+(res<<3)+(c^48);
return res*f;
}
struct EDGE{
int u,v,w,nxt;
}e[MAXN<<1];
struct NODE{
int u,d;
bool operator < (const NODE&rhs) const {return d>rhs.d;}
};
int cnt,head[maxn];
void add(int u,int v,int w){
e[++cnt]=(EDGE){u,v,w,head[u]};
head[u]=cnt;
}
priority_queue<NODE> Q;
int d[12][maxn];
void Dijstra(int dis[],int s){
Q.push((NODE){s,0}); dis[s]=0;
while(!Q.empty()){
int u=Q.top().u,d=Q.top().d; Q.pop();
if(d!=dis[u]) continue;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].v,w=e[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
Q.push((NODE){v,dis[v]});
}
}
}
}
int n,m,k,p[12],f[12][12][1<<12],ans[12],Ans,Ans_u;
bool vis[maxn];
int main(){
memset(d,0x3f,sizeof d); memset(f,0x3f,sizeof f); memset(ans,0x3f,sizeof ans); Ans=INF;
n=read(); m=read(); k=read();
for(int i=0;i<k;i++) p[i]=read(),vis[p[i]]=1;
for(int i=1;i<=m;i++){
int x=read(),y=read(),w=read();
add(x,y,w); add(y,x,w);
}
for(int i=0;i<k;i++) Dijstra(d[i],p[i]);
for(int i=0;i<k;i++){
f[i][i][1<<i]=0;
for(int s=0;s<1<<k;s++)if(s&1<<i){
for(int j=0;j<k;j++)if(s&1<<j){
for(int l=0;l<k;l++)if(!(s&1<<l)){
f[i][l][s|1<<l]=min(f[i][l][s|1<<l],f[i][j][s]+d[j][p[l]]);
}
}
}
for(int j=0;j<k;j++) ans[i]=min(ans[i],f[i][j][(1<<k)-1]);
}
for(int i=1;i<=n;i++)if(!vis[i]){
for(int j=0;j<k;j++){
if(ans[j]+d[j][i]<Ans){
Ans=ans[j]+d[j][i];
Ans_u=i;
}
}
}
printf("%d %d\n",Ans_u,Ans);
}