题意:

有 n n n个地方,他们被 m m m条道路相连。有一天, t o t tot tot个人在 1 1 1处开派对,开完派对他们要回家,他们回家只会走最短路径,其中有 k ( k ≤ 6 ) k(k\leq6) k(k≤6)个人没车,而有车的人可以捎带这些没车的人,但前提是他们的家在开车的人的回家的路径上。问最少有多少个人只能走路回家?

Soluton:

显然我们只需要处理出每个开车的人可能捎带的组合,然后状压 d p dp dp即可,设 d p [ i ] [ s ] dp[i][s] dp[i][s]为前 i i i个人,他们能捎带的总集合为 s s s是否有可能,我们处理完每个开车的人的捎带组合 s i s_{i} si​,那么在前 i − 1 i-1 i−1个人的捎带集合 s s s是有可能的情况下

d p [ i ] [ s ∣ s i ] = t r u e dp[i][s|s_{i}]=true dp[i][s∣si​]=true

那么问题就在如何捎带出来,一种方法是先处理出最短路径长度,然后 d f s dfs dfs找出每条路径可稍带的组合,然后 d p dp dp,这样的时间复杂度太大,本来过得了,加了 h a c k hack hack数据就过不了了,这是dfs版本代码

#include<bits/stdc++.h>
using namespace std;using ll=long long;
const int N=10005,inf=0x3fffffff;
const long long INF=0x3f3f3f3f3f3f,mod=998244353;struct way
{int to,next;
}edge[N<<1];
int cnt,head[N];void add(int u,int v)
{edge[++cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;
}int n,m,tot,k,walk[N],loc[N],dis[N],ccnt,disall;
bool car[N],dp[N][1<<6],vis[N];
vector<vector<int>>from(N);void dijkstra()
{priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;dis[1]=0;q.push({dis[1],1});while(!q.empty()){int u=q.top().second; q.pop();if(vis[u]) continue;vis[u]=true;for(int i=head[u];i;i=edge[i].next){int v=edge[i].to;if(dis[u]+1<dis[v]) {from[v].clear();from[v].push_back(u);dis[v]=dis[u]+1;q.push({dis[v],v});}else if(dis[u]+1==dis[v]) from[v].push_back(u);}}
}int find(int u)
{int ret=0;for(int i=1;i<=k;i++)if(loc[walk[i]]==u) ret|=1<<(i-1);return ret;
}int calc(int s)
{int ret=0;for(int i=0;i<k;i++) ret+=(s>>i)&1^1;return ret;
}void dfs(int u,int s,int ddis)
{int ns=s|find(u);if(u==1){for(int i=0;i<(1<<k);i++) if(dp[ccnt-1][i]) dp[ccnt][i|s]=true;return;}if(ddis>=disall) return;for(auto v:from[u]) dfs(v,ns,ddis+1);
}void init()
{cin>>n>>m; cnt=ccnt=0;for(int i=1;i<=n;i++){head[i]=0;vis[i]=false;dis[i]=inf;from[i].clear();}for(int i=1;i<=m;i++){int u,v; scanf("%d%d",&u,&v);add(u,v); add(v,u);}scanf("%d",&tot);for(int i=1;i<=tot;i++){scanf("%d",&loc[i]);car[i]=true;}scanf("%d",&k);for(int i=1;i<=k;i++){scanf("%d",&walk[i]);car[walk[i]]=false;}for(int i=0;i<=tot;i++)for(int j=0;j<(1<<k);j++) dp[i][j]=false;dijkstra();
}void work()
{init();for(int i=1;i<=tot;i++){if(!car[i]) continue;dp[ccnt++][0]=true;disall=dis[loc[i]];dfs(loc[i],find(loc[i]),0);}int ans=k;for(int s=0;s<(1<<k);s++)if(dp[ccnt][s]) ans=min(ans,calc(s));printf("%d\n",ans);
}int main()
{int T; cin>>T;while(T--) work();    return 0;
}

考虑优化他,可以在最短路的过程上再状压 d p dp dp,设 t a k e [ u ] [ s ] take[u][s] take[u][s]为从1到 u u u的最短路上捎带集合为 s s s是否有可能,显然一开始 t a k e [ u ] [ 0 ] = t r u e take[u][0]=true take[u][0]=true,那么在dijkstra中,用 u u u更新 v v v的时候,就可以把 u u u的take更新到 v v v去,此时需要先情况 t a k e [ v ] take[v] take[v],或者在 d i s [ u ] + 1 = = d i s [ v ] dis[u]+1==dis[v] dis[u]+1==dis[v]的时候更新 v v v,此时不用清空 t a k e [ v ] take[v] take[v]

需要注意的是,状压的是第几个没车的人的被捎带情况如何,而不是第几个人,这题的映射有点多

#include<bits/stdc++.h>
using namespace std;using ll=long long;
const int N=10005,inf=0x3fffffff;
const long long INF=0x3f3f3f3f3f3f,mod=998244353;struct way
{int to,next;
}edge[N<<1];
int cnt,head[N];void add(int u,int v)
{edge[++cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;
}int n,m,tot,k,loc[N],dis[N],live[N],ccnt;
bool take[N][1<<6],vis[N],car[N],dp[N][1<<6];void clear(int u)
{for(int i=1;i<(1<<k);i++) take[u][i]=false;
}void upd(int u,int v)
{for(int i=0;i<(1<<k);i++)if(take[u][i]) take[v][i|live[v]]=true;
}void dijkstra()
{priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;q.push({dis[1]=0,1});while(!q.empty()){int u=q.top().second; q.pop();if(vis[u]) continue;vis[u]=true;for(int i=head[u];i;i=edge[i].next){int v=edge[i].to;if(dis[u]+1<dis[v]){clear(v); upd(u,v);q.push({dis[v]=dis[u]+1,v});}else if(dis[u]+1==dis[v]) upd(u,v);}}
}int calc(int s)
{int ret=0;for(int i=0;i<k;i++) ret+=(s>>i)&1^1;return ret;
}void init()
{scanf("%d%d",&n,&m);cnt=ccnt=0;for(int i=1;i<=n;i++) head[i]=live[i]=0;while(m--){int u,v; scanf("%d%d",&u,&v);add(u,v); add(v,u);}scanf("%d",&tot);for(int i=1;i<=tot;i++){scanf("%d",&loc[i]);car[i]=true;}scanf("%d",&k);for(int i=1;i<=k;i++){int x; scanf("%d",&x);car[x]=false;live[loc[x]]|=1<<(i-1);}for(int i=1;i<=tot;i++)for(int j=0;j<(1<<k);j++) dp[i][j]=false; for(int i=1;i<=n;i++){for(int j=0;j<(1<<k);j++) take[i][j]=false;take[i][0]=true; dis[i]=inf; vis[i]=false;}dijkstra();
}void work()
{init();for(int i=1;i<=tot;i++){if(!car[i]) continue;dp[ccnt++][0]=true;for(int j=0;j<(1<<::k);j++)for(int k=0;k<(1<<::k);k++)if(dp[ccnt-1][j]&&take[loc[i]][k]) dp[ccnt][j|k]=true;}int ans=k;for(int i=0;i<(1<<k);i++)if(dp[ccnt][i]) ans=min(ans,calc(i));printf("%d\n",ans);
}int main()
{int T; cin>>T;while(T--) work();    return 0;
}

Codeforces 1741G 最短路上状压dp相关推荐

  1. CodeForces - 1550E Stringforces(二分+状压dp)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串,只包含前 kkk 个小写字母以及通配符 ???,现在可以将通配符替换成任意的前 kkk 个字母中的一个.设 f[i]f[i]f[i] 为 ...

  2. Codeforces ----- Kefa and Dishes [状压dp]

    题目传送门:580D 题目大意:给你n道菜以及每道菜一个权值,k个条件,即第y道菜在第x道后马上吃有z的附加值,求从中取m道菜的最大权值 看到这道题,我们会想到去枚举,但是很显然这是会超时的,再一看数 ...

  3. CodeForces - 1523D Love-Hate(随机数+状压dp)

    题目链接:点击查看 题目大意:给出 nnn 个 010101 序列表示二进制状态,问选择至少 ⌈n2⌉\lceil \frac{n}{2}\rceil⌈2n​⌉ 个状态进行位运算的与运算后得到的答案中 ...

  4. 牛客 - 收集纸片(最短哈密顿路径-状压dp)

    题目链接:点击查看 题目大意:给出一个 n * m 的二维平面,其中有 k 个纸片,给出第一个纸片的位置,要求从第一个纸片出发,经过每个纸片一次后再回到第一个纸片的位置,输出最短路径 题目分析:最短哈 ...

  5. HDU - 3538 A sample Hamilton path(最短哈密顿路径+状压dp)

    题目链接:点击查看 题目大意:求从0开始的最短哈密顿路径,并且要求了某些点的先后顺序 题目分析:哈密顿路径:由指定的起点前往指定的终点,途中经过所有其他节点且只经过一次(百度百科) 既然按照一定的次序 ...

  6. CodeForces - 1316E Team Building(状压dp)

    题目链接:点击查看 题目大意:给出 n 个人,现在需要 p 个球员和 k 个啦啦队员,n 个人当啦啦队员以及当第 i 个位置的球员所做的贡献都会给出,现在问如何分配可以使得总贡献和最大 题目分析:因为 ...

  7. Codeforces Beta Round #8 C. Looking for Order 状压dp

    题目链接: http://codeforces.com/problemset/problem/8/C C. Looking for Order time limit per test:4 second ...

  8. Codeforces Gym 100676G Training Camp 状压dp

    http://codeforces.com/gym/100676 题目大意是告诉你要修n门课,每门课有一个权值w[i], 在第k天修该课程讲获得k*w[i]的学习点数,给出了课程与先修课程的关系,要修 ...

  9. Educational Codeforces Round 13 E. Another Sith Tournament 状压dp

    E. Another Sith Tournament 题目连接: http://www.codeforces.com/contest/678/problem/E Description The rul ...

最新文章

  1. 计算机网页设计布局与排版研究,论计算机网页设计的布局与排版
  2. 你花了多久弄明白架构设计?java多线程编程实战指南pdf
  3. 什么是防火墙?—Vecloud微云
  4. Oracle使用sqlplus登录用户尽量使用nolog登录
  5. Java数组的转换和拷贝
  6. 『总结』CSS/CSS3常用样式与web移动端资源
  7. DSP sawtooth锯齿波与square方波matlab产生(M2.2)
  8. Python BeautifuSoup4 爬表格
  9. 傅里叶光学MATLAB编程系列【1】基本函数
  10. 《30天自制操作系统》 day8 小结
  11. mysql表名命名规范_数据库表名的命名规范
  12. 微信红包系统设计方案
  13. 如何用python修改安卓和iOS的微信和支付宝步数!
  14. UPC6605: 所罗门王的宝藏
  15. Mc1.16forge官混教程/教补-#6 原版配方数据包
  16. cesium中实现热力图
  17. 百度离线地图金字塔瓦片发布
  18. Html5常见面试题总结
  19. 缓冲区溢出漏洞_缓冲区溢出漏洞简介
  20. uni-app z-index无效的解决办法(遮罩层)

热门文章

  1. 基于java下的Springboot框架实现幼儿园管理系统
  2. 2018dnf服务器维护时间,dnf2018年5月电脑管家活动_2018dnf5月电脑管家活动网址_快吧游戏...
  3. Android果冻效果滑动控件
  4. xadsafe做暗刷_我叫MT3.61四暗影刷法攻略方法
  5. VS创建ATL项目,ActiveX控件
  6. 使用 JavaScript 进行HTML表格排序
  7. 仙道录 第一卷 天道门 第十章 大长老之死
  8. 为日语视频识别生成中文字幕的免费且快速简单的解决方案
  9. 国内外著名IT公司技术岗位要求
  10. 【苹果传文件】【苹果手机文件传输】windows系统 iPhone手机文件传输 win系统苹果手机【苹果传电影】【苹果传图片】【一眼就会】