[TK] Tourist Attractions
题目描述
给出一张有
你需要找一条从
每个限制条件形如
注意,这里的停留不是指经过。
解法分析
对于这道题的状压. 我们考虑枚举 "现在已经在哪些点停留" 这样一种状态. 然后去寻找每一个当前未停留的点,考虑这个点的前置节点是否全部已经停留,如果是,那么枚举每一个已在集合内的节点,尝试把这个点通过某条边放入集合内,进行状态转移.
那么我们需要进行状态压缩的有两个东西: 现在已有的点的情况 (用于枚举) 和每个点的前置节点情况 (用于判断).
最后需要我们输出的就是在全部节点停留情况下的状态.
这道题的主要思路:
for(int i=1;i<=(1<<k)-1;++i){
//all possible chance
for(int j=0;j<=k-1;++j){ //node
if(i&(1<<j)){
//if this node in this chance
for(int hdk=0;hdk<=k-1;++hdk){
//then try to add a node
if(!(i&(1<<hdk))&&((i|r[hdk+2])==i)){
//if find a node not in chance and can be placed
update();
}
//then do the change. why it's +2 is because I store 3 in position 1.(1 and 2 is no need)
}
}
}
}
那么,为了更新已选中的点的距离,我们需要知道从任意点到另一点的距离,也就是跑一边全源最短路.
我们定义
那么我们怎么表示
这题我也不知道它卡什么. 我存图的 vector 滚动数组会比前向星小很多,而 DIJ 又比 SPFA 快很多. 总之按对的来吧.
代码实现
#include<bits/stdc++.h>
using namespace std;
int n,m,k;
struct edge{
int to,w;
};
struct node{
int id,dis;
bool operator<(const node A)const{
return dis>A.dis;
}
};
priority_queue<node> q;
vector<edge> e[20001];
int dis[31][20001]; //root i's dis j
bool vis[20001];
void dij(int s){
memset(vis,false,sizeof vis);
for(int i=1;i<=n;++i){
dis[s][i]=1000000000;
}
while(!q.empty()) q.pop();
dis[s][s]=0;
q.push(node{s,0});
while(!q.empty()){
node u=q.top();
q.pop();
if(vis[u.id]) continue;
vis[u.id]=true;
for(edge i:e[u.id]){
if(dis[s][i.to]>dis[s][u.id]+i.w){
dis[s][i.to]=dis[s][u.id]+i.w;
q.push(node{i.to,dis[s][i.to]});
}
}
}
}
int f[1<<20][31],r[31],ans=1000000000; //1=zt(which nodes been chose) 2=node //r= mustfore
int main(){
cin>>n>>m>>k;
for(int i=1;i<=m;++i){
int a,b,c;
cin>>a>>b>>c;
e[a].push_back(edge{b,c});
e[b].push_back(edge{a,c});
}
if(k==0){
dij(1);
cout<<dis[1][n];
return 0;
}
int q;
cin>>q;
while(q--){
int a,b;
cin>>a>>b;
r[b]+=(1<<(a-2));//
}
for(int i=1;i<=k+1;++i){
dij(i);
}
for(int i=0;i<=(1<<k)-1;++i){
for(int j=1;j<=k+1;++j){
f[i][j]=1000000000;
}
}
f[0][1]=0;
for(int i=2;i<=k+1;++i){
if(!r[i]){ //if this point hasn't any requires.
f[1<<(i-2)][i]=dis[1][i];
}
}
for(int i=1;i<=(1<<k)-1;++i){ //all possible chance
for(int j=0;j<=k-1;++j){ //node
if(i&(1<<j)){ //if this node in this chance
for(int hdk=0;hdk<=k-1;++hdk){ //then try to add a node
if(!(i&(1<<hdk))&&((i|r[hdk+2])==i)){ //if find a node not in chance and can be placed
f[i|(1<<hdk)][hdk+2]=min(f[i|(1<<hdk)][hdk+2],f[i][j+2]+dis[j+2][hdk+2]);
} //then do the change. why it's +2 is because I store 3 in position 1.(1 and 2 is no need)
}
}
}
}
for(int i=2;i<=k+1;++i){
ans=min(ans,f[(1<<k)-1][i]+dis[i][n]);
}
cout<<ans;
}
洛谷数据需要滚动数组优化,正在写.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!