题目
分析
k ≤ 12 k\leq12 k≤12,果断考虑状压。
将所有必须走的边的端点 u , v u,v u,v视为关键点,为每个关键点跑Dijkstra,然后状压DP。
d
p
[
S
]
[
i
]
[
0
]
dp[S][i][0]
dp[S][i][0]表示走完集合为
S
S
S的边,最后停在第
i
i
i条边的
u
u
u点的最小代价;
d
p
[
S
]
[
i
]
[
1
]
dp[S][i][1]
dp[S][i][1]表示走完集合为
S
S
S的边,最后停在第
i
i
i条边的
v
v
v点的最小代价。
每次转移考虑从上一条边的 u , v u,v u,v走最短路走过来,再强制走边 u ↔ v u\leftrightarrow v u↔v。
有个问题是要求从 1 1 1开始,又回到 1 1 1,其实很简单:把边 ( u = 1 , v = 1 , w = 0 ) (u=1,v=1,w=0) (u=1,v=1,w=0)作为关键边再跑状压DP,并且状压的集合里要求必须有这条边,就可以了。
代码
可能是我写得太丑了被卡常,用了超级读入挂+vector
+register
才过,少一样都不行。
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#ifndef LOACL
#define getchar() (*(IOB.in.p++))
#define putchar(c) (*(IOB.out.p++) = (c))
#define io_eof() (IOB.in.p >= IOB.in.pend)
struct IOBUF {
struct {
char buff[1 << 27], *p, *pend;
} in;
struct {
char buff[1 << 27], *p;
} out;
IOBUF() {
in.p = in.buff, out.p = out.buff;
in.pend = in.buff + fread(in.buff, 1, 1 << 27, stdin);
}
~IOBUF() {
fwrite(out.buff, 1, out.p - out.buff, stdout);
}
} IOB;
#endif
template <typename IO>
inline void write(IO val) {
if(val == 0) {
putchar('0');
return;
}
if(val < 0) {
putchar('-');
val = -val;
}
static char buf[30];
char *p = buf;
while(val) {
*(p++) = val % 10 + '0';
val /= 10;
}
while(p > buf) putchar(*(--p));
}
inline void writestr(const char *s) {
while(*s != 0) putchar(*(s++));
}
template <typename IO>
inline void writeln(IO val) {write(val), putchar('\n');}
template <typename IO>
inline void writesp(IO val) {write(val), putchar(' ');}
inline int readstr(char *s) {
char *begin = s, c = getchar();
while(c < 33 || c > 127)
c = getchar();
while(c >= 33 && c <= 127)
*(s++) = c, c = getchar();
*s = 0;
return s - begin;
}
template <typename IO>
inline IO read() {
IO ret = 0;
register bool w = 0;
register char c = getchar();
while(c > '9' || c < '0') {
if(c == '-') w = 1;
c = getchar();
}
while(c >= '0' && c <='9') {
ret = (ret << 3) + (ret << 1) + (c ^ 48);
c = getchar();
}
return w ? -ret : ret;
}
#define MAXK (12+1)
#define MAXN 50000
#define MAXM 200000
#define LL long long
#define INF 1000000000000000000ll
#define PII pair<int,int>
#define PLI pair<long long,int>
int N,M,K;
int KeyNode[MAXN+5];
vector<PII> G[MAXN+5];
struct Edge{
int u,v,w;
}E[MAXM+5];
struct DistNode{
int u;LL d;
DistNode(){}
DistNode(int x,int y):
u(x),d(y){}
bool operator < (const DistNode other) const{
return d>other.d;
}
};
LL Dist[2*MAXK+5][MAXN+5];
void Dijkstra(int S,LL *Dist,PII Ban){
priority_queue<DistNode> Q;
fill(Dist+1,Dist+N+1,INF);
Q.push(DistNode(S,Dist[S]=0));
while(!Q.empty()){
int u=Q.top().u;LL d=Q.top().d;Q.pop();
if(d>Dist[u]) continue;
for(register int i=0;i<int(G[u].size());i++){
int v=G[u][i].first,w=G[u][i].second;
if((u==Ban.first&&v==Ban.second)||
(u==Ban.second&&v==Ban.first))
continue;
if(Dist[v]>Dist[u]+w){
Dist[v]=Dist[u]+w;
Q.push(DistNode(v,Dist[v]));
}
}
}
}
#define MAXS (1<<MAXK)
LL dp[MAXS+5][MAXK+5][2];
int main(){
int cnt=0;
N=read<int>(),M=read<int>(),K=read<int>();
K++;
E[1].u=E[1].v=1,E[1].w=0;
for(register int i=1;i<=M;i++){
int u=read<int>(),v=read<int>(),w=read<int>();
G[u].push_back(make_pair(v,w));
G[v].push_back(make_pair(u,w));
E[i+1].u=u,E[i+1].v=v,E[i+1].w=w;
}
for(register int i=1;i<=K;i++){
int u=E[i].u,v=E[i].v;
if(!KeyNode[u])
Dijkstra(u,Dist[KeyNode[u]=++cnt],make_pair(u,v));
if(!KeyNode[v])
Dijkstra(v,Dist[KeyNode[v]=++cnt],make_pair(u,v));
}
register int All=(1<<K)-1;
dp[1][1][0]=dp[1][1][1]=0;
for(register int S=2;S<=All;S++)
dp[S][1][0]=dp[S][1][1]=INF;
for(register int S=3;S<=All;S+=2){
for(register int i=2;i<=K;i++){
if(!(S&(1<<(i-1))))
continue;
int T=S^(1<<(i-1));
int iu=E[i].u,iv=E[i].v,iw=E[i].w;
dp[S][i][0]=dp[S][i][1]=INF;
for(register int j=1;j<=K;j++){
if(i==j||(!(S&(1<<(j-1)))))
continue;
int ju=E[j].u,jv=E[j].v;
int juk=KeyNode[ju],jvk=KeyNode[jv];
dp[S][i][0]=min(dp[S][i][0],min(dp[T][j][0]+Dist[juk][iv]+iw,dp[T][j][1]+Dist[jvk][iv]+iw));
dp[S][i][1]=min(dp[S][i][1],min(dp[T][j][0]+Dist[juk][iu]+iw,dp[T][j][1]+Dist[jvk][iu]+iw));
}
}
}
LL Ans=INF;
for(register int i=2;i<=K;i++){
int iuk=KeyNode[E[i].u],ivk=KeyNode[E[i].v];
Ans=min(Ans,min(dp[All][i][0]+Dist[iuk][1],dp[All][i][1]+Dist[ivk][1]));
}
printf("%lld",Ans);
}