题意:
有n个从1到n的点在一维上,他们之间有些边,你要访问其中至少k个点,每个点只能被访问一次且被访问过的点之后不能再路过:3->2->4这种就是路过了3,是不被允许的。
题解:
爆搜+剪枝也会t啊,可能我写的不够优秀,但是记忆化搜索就可以过。这个很容易想到dp[i][j][l][r],表示的是在第i个点,访问了j个位置,接下来能够访问的区间不超过l,r最短路径是多少。
那么我们枚举一开始的点,在之后的访问的时候,如果下一个点在当前点的左边的时候,那么之后的范围就是当前的l和当前点为r:假设有6个点,一开始的l,r为0,7,那么我从2开始,到4的话,之后的l,r就是2,7。
#include<bits/stdc++.h>
using namespace std;
int n,k;
struct node
{
int to,next,w;
}e[4005];
int cnt,head[100];
void add(int x,int y,int w)
{
e[cnt].to=y;
e[cnt].next=head[x];
e[cnt].w=w;
head[x]=cnt++;
}
int ans=1e9,mw[4005];
int dp[81][81][81][81];
int dfs(int pos,int x,int l,int r)
{
if(pos>=k)
return 0;
int &aa=dp[x][pos][l][r];
if(~aa)
return aa;
int ans=1e9;
for(int i=head[x];~i;i=e[i].next)
{
int ne=e[i].to;
if(ne<=l||ne>=r)
continue;
if(ne<x)
ans=min(ans,dfs(pos+1,ne,l,x)+e[i].w);
else
ans=min(ans,dfs(pos+1,ne,x,r)+e[i].w);
}
aa=ans;
return ans;
}
int main()
{
memset(dp,-1,sizeof(dp));
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&k);
int m,all=0;
scanf("%d",&m);
int x,y,w;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&w);
if(x!=y)
add(x,y,w),mw[++all]=w;
}
m=all;
sort(mw+1,mw+1+m);
for(int i=1;i<=m;i++)
mw[i]+=mw[i-1];
int ans=1e9;
for(int i=1;i<=n;i++)
ans=min(ans,dfs(1,i,0,n+1));
printf("%d\n",ans==1e9?-1:ans);
return 0;
}