HDU 6166 2017多校 Team09 1006:Dijkstra顶点子集最短路径

来源:互联网 发布:什么是数据api接口 编辑:程序博客网 时间:2024/06/05 20:56

宕掉了好几天。。。。。来发一个水题的题解

题意:给出一个有向图(n,m<=1e5),并给出一个询问集合,请求出集合中的点,两两之间的最短距离。

题解:回想最短路算法,首先排除掉N^3的的那个,然后剩下SPFA和Dijkstra跑多次的复杂度比较能接受,这两个其实是差不多的东西,由于边权都是正的,就上Dijkstra吧。

基础版的Dijkstra是单源多汇的,但是本题是多源多汇,但是Dij他是单源的……等等。。。Dij也可以多源呀,只要开一个超源0,用长度为0的边连接到各个起点,在把每个终点用长度为0的边连接到超汇n+1,这样0 - n+1的最短路就是从所有的起点到所有的终点路径中最短的。那么我们要想办法把真正最短答案的起点 分到起点集合中,把真正的最优终点放到终点集合,其他的随便放哪里都行。emmmm随机化算法随机分组。。。期望做4次可以得到正确答案。。。。

官解:按照点的标号的每个二进制位分组,最多分20次(准确的说是17次)。每次会把某一位不同的点分开到起点和终点集,然后再起点终点互换,再做一次。

正确性在于:对于任意两个点u和v,u和v是不同的点,必然有至少一个位不同,因此至少有一次他们被分到了各自正确的集合中,得到了正确答案,其他的答案都比他要大。

注意:这个题好像卡了vector的常数。。。模拟链表可以过掉。但是好像大家都是随机化算法搞得。。。

拓展:如果题目中没有环,还有另外一种哦做法:对于每个询问点x,连接0->x长度为0的边,对于每个点 i ,如果i有连接到某个询问点的边,那么把这条边重定向到 n+1点,从0到n+1跑一次就是答案。这个题的话。。。因为环路的存在。。。所以诸如1->2->3->1这样的道路也被统计到了。。。就得到了非法答案。。。。我也想不到什么好的方法。。。只好放弃了。。

PS:上面这个思路是我十分钟极限操作出来的。写的时候就担心有环。。最后果然WA了。

Code:

#include <stdio.h>#include <algorithm>#include <iostream>#include <queue>using namespace std;#define N 100010#define INF 0x3f3f3f3f3f3f3f3fLL#define LL long long#define p E[i].x#define bit(x) (1<<(x))using namespace std;struct node{int x;LL v;bool operator<(const node &tmp)const{return v>tmp.v;}};priority_queue<node> q;struct edge{int x,to,v;}E[N<<1];int n,m,totE,g[N],X[N],Y[N],Z[N],a[N];LL dist[N];bool v[N];void addedge(int x,int y,int v){E[++totE] = (edge){y,g[x],v}; g[x] = totE;}LL calc_dist(int S,int T){for(int i=0;i<=n+1;i++) dist[i] = INF, v[i] = 0;dist[S]=0;q.push((node){S,0});node tmp;while(!q.empty()){tmp = q.top(); q.pop();int x = tmp.x;if(v[x]) continue;v[x] = 1;for(int i=g[x];i;i=E[i].to)if(!v[p] && dist[p]>dist[x]+E[i].v){dist[p] = dist[x] + E[i].v;q.push((node){p,dist[p]});}}return dist[T];}int main(){    //freopen("in0.txt","r",stdin);int T,K,Te = 0;cin>>T;while(T--){scanf("%d%d",&n,&m);for(int i=1;i<=m;i++) scanf("%d%d%d",&X[i],&Y[i],&Z[i]);scanf("%d",&K);for(int i=1;i<=K;i++) scanf("%d",&a[i]);LL ans = INF;for(int t=0;t<20;t++){totE = 0;for(int i=0;i<=n+1;i++) g[i] = 0;for(int i=1;i<=m;i++) addedge(X[i],Y[i],Z[i]);for(int i=1;i<=K;i++){if(a[i]&bit(t)) addedge(0,a[i],0);else addedge(a[i],n+1,0);}ans = min(ans, calc_dist(0,n+1));totE = 0;for(int i=0;i<=n+1;i++) g[i] = 0;for(int i=1;i<=m;i++) addedge(X[i],Y[i],Z[i]);for(int i=1;i<=K;i++){if((a[i]&bit(t))==0) addedge(0,a[i],0);else addedge(a[i],n+1,0);}ans = min(ans, calc_dist(0,n+1));}//assert( ans < INF );printf("Case #%d: %lld\n",++Te,ans);}return 0;}


原创粉丝点击