zoukankan      html  css  js  c++  java
  • 【日常训练】【BZOJ】20210304_T1_旅行travel_图论/最短路/Dijkstra_Bzoj4681

    题面

    HZY 喜欢旅游,这次她打算去一个据说有很多漂亮瀑布的山谷玩。

    HZY 事先得到了一张地图,上面标注了 N 个小动物的聚居地,也就是一个个的小村落。其中第 1 个村庄是 HZY 现在住的地方,第 N 个村庄是 WJJ 打算去的地方。这些村庄之间有 M 条双向道路连接着,第 i 条双向道路恰好直接连接两个小村庄 A, B,长度为 C(1< = A, B < = N, A!=B, 1< = C< = 1000)。

    道路有的是隧道,有的是栈桥,地图上那些看起来在村庄之外交叉的路实际上并不相交——也就是说,如果把这些小村落和双向道路构成的道路网看作图论意义上的图,我们不保证它是平面图,也不保证它没有重边。不过,有一点还是可以保证的: HZY细心地验证过, 从它居住的村落一定能走到她想去的那个山谷。

    在 HZY 所在的神奇世界中,每只小动物都可以借助仙人掌来施放魔法,其中之一是, 交换世界中任意两条双向道路的长度,同时保持其他道路的长度不变。

    按 HZY 目前的魔法水平,她最多能使用 K 次这种道路长度交魔法。可惜的是,由于仙人掌刺比较多, HZY 并不打算带着它旅行,于是她会在家里完成想要的道路交换后再出门。假设 HZY 的旅行途中不会有其他小动物进行道路交换来破坏她设计好的路线。为了尽快达到目的地, HZY 希望她需要走的总距离越短越好。也就是说, 使用最多 K 次魔法后,从村落 1 到村落 N 的最短距离是多少?

    对于前 10%的数据,N≤10;

    对于前 30%的数据,N≤20;

    对于前 40%的数据,K≤4;

    对于 100%的数据,2≤N≤50,1≤M≤150,K≤20。

    黑暗爆炸OJ 4681

    题解

    现场得分:30/100

    因为我dp的第二维应该是到(k)的,但是因为没有想清楚,在初始化dp数组的时候第二维到(n)了。

    • 我们考虑如果一条最短的路径,一定是把某一条路径其中最大的(k)条边变成了最短的(k)条边。假设我们这条路径上[(经过变化的边)中变化后最大的那条边]变成了所有边中排名第(j)的边,则所有排名小于等于(j)的边一定是全部使用了的。(如果有边边权相等,任取即可,不影响)
    • 那么我们可以枚举一个(j),表示强制要求边权前(j)小的边全部使用,我们的答案是多少。我们可以通过(f_{i,d,h})表示到第(i)个点,当前变化了(d)次,前(j)个中已经用了(h)个的情况下,走过的边权不在前(j)小的边权和最小值。
    • 直接Dij转移,复杂度(O(n^2km))

    代码

    #include<bits/stdc++.h>
    #define LL long long
    #define U unsigned
    #define MAXN 51
    #define MAXM 160
    #define MAXK 21
    using namespace std;
    template<typename T> void Read(T &cn)
    {
    	char c; int sig = 1;
    	while(!isdigit(c = getchar())) if(c == '-') sig = 0;
    	if(sig) {cn = c-48; while(isdigit(c = getchar())) cn = cn*10-48+c; }
    	else    {cn = 48-c; while(isdigit(c = getchar())) cn = cn*10+48-c; }
    }
    template<typename T> void Write(T cn)
    {
    	T cm = 0; int wei = 0, cx = cn%10; cn = cn/10;
    	if(cn < 0 || cx < 0) {putchar('-'); cn = -cn; cx = -cx; }
    	while(cn) wei++, cm = cm*10+cn%10, cn = cn/10;
    	while(wei--) putchar(cm%10+48), cm = cm/10;
    	putchar(cx+48);
    }
    template<typename T> void WriteL(T cn) {Write(cn); puts(""); }
    template<typename T> void WriteS(T cn) {Write(cn); putchar(' '); }
    template<typename T> void Max(T &cn, T cm) {cn = cn < cm ? cm : cn; }
    template<typename T> void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; }
    struct qwe{
    	int a,b,ne,w,pai;
    	void mk(int cn, int cm, int cx, int cw) {a = cn; b = cm; ne = cx; w = cw; }
    };
    struct qwer{
    	int i, d, h, zhi, pos;
    	void mk(int ci, int cd, int ch, int cz, int cp) {i = ci; d = cd; h = ch; zhi = cz; pos = cp; }
    	inline friend bool operator <(qwer cn, qwer cm) {return cn.zhi == cm.zhi ? (cn.pos < cm.pos) : cn.zhi > cm.zhi; }
    };
    qwe a[MAXM*2+1];
    int alen;
    int head[MAXN+1];
    int n,m,k,curj,curk;
    int f[MAXN+1][MAXK+1][MAXN+1];
    qwer dui[MAXN*MAXK*MAXM*2+1];
    int dlen, plen;
    void lian(int cn, int cm, int cx) {a[++alen].mk(cn,cm,head[cn],cx); head[cn] = alen; }
    void zeng(int ci, int cd, int ch, int cz) 
    {
    	if(ch > curj || cd > ch) return;
    	if(cd > curk) return;
    	if(f[ci][cd][ch] <= cz) return;
    	f[ci][cd][ch] = cz; 
    	++plen; dui[++dlen].mk(ci, cd, ch, cz, plen); push_heap(dui+1,dui+dlen+1); 
    }
    void suan()
    {
    //	printf("in suan : curj = %d
    ",curj);
    	plen = dlen = 0;
    	for(int i = 1;i<=n;i++) for(int d = 0;d<=curk;d++) for(int h = 0;h<=curj;h++) f[i][d][h] = 2000*n;
    	zeng(1, 0, 0, 0);
    	while(dlen)
    	{
    		while(dlen && (f[dui[1].i][dui[1].d][dui[1].h] != dui[1].zhi)) pop_heap(dui+1,dui+(dlen--)+1);
    		if(!dlen) return;
    		int dang = dui[1].i, bx = dui[1].d, by = dui[1].h, bz = dui[1].zhi;
    //		printf("  dang = %d bx = %d by = %d bz = %d
    ",dang,bx,by,bz);
    		pop_heap(dui+1,dui+(dlen--)+1);
    		for(int i = head[dang];i;i = a[i].ne)
    		{
    			int y = a[i].b;
    			if(a[i].pai <= curj) {zeng(y, bx, by+1, bz); continue; }
    			zeng(y, bx+1, by+1, bz);
    			zeng(y, bx, by, bz+a[i].w);
    		}
    	}
    }
    signed main()
    {
    //	freopen("travel.in","r",stdin);
    //	freopen("travel.out","w",stdout);
    	Read(n); Read(m); Read(k);
    	alen = 0; memset(head,0,sizeof(head));
    	for(int i = 1;i<=m;i++) {int bx,by,bz; Read(bx); Read(by); Read(bz); lian(bx,by,bz); lian(by,bx,bz); }
    	for(int i = 1;i<=m;i++)
    	{
    		a[i*2].pai = 1;
    		for(int j = 1;j<i;j++) if(a[i*2].w >= a[j*2].w) a[i*2].pai++;
    		for(int j = i+1;j<=m;j++) if(a[i*2].w > a[j*2].w) a[i*2].pai++;
    		a[i*2-1].pai = a[i*2].pai;
    //		printf("a[%d].pai = %d
    ",i*2,a[i*2].pai);
    	}
    	int ans = 2000*n;
    	for(int i = 0;i<=n;i++) 
    	{
    		curj = i; curk = min(i,k); suan();
    		int lin = 2000*n;  
    		for(int d = 0;d<=curk;d++) for(int h = 0;h<=i;h++) Min(lin, f[n][d][h]);
    		for(int j = 1;j<=m;j++) if(a[j*2].pai <= i) lin = lin + a[j*2].w;
    //		printf("i = %d lin = %d
    ",i,lin);
    		Min(ans, lin);
    	}
    	WriteL(ans);
    	return 0;
    }
    
  • 相关阅读:
    软件概要设计说明书(初稿) 定稿
    重新确定了数据流图以及模块图2020.5.4
    开始编写概要说明书以及详细说明书2020.4.29
    singleflight是如何避免缓存击穿的?
    从IO 到BIO/NIO/AIO 浅析
    JVM
    Http
    Linux命令
    什么时候触发MinorGC?什么时候触发FullGC?
    计算机网络
  • 原文地址:https://www.cnblogs.com/czyarl/p/14482409.html
Copyright © 2011-2022 走看看