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;
    }
    
  • 相关阅读:
    杭电 Problem
    杭电Problem 5053 the sum of cube 【数学公式】
    杭电 Problem 2089 不要62 【打表】
    杭电 Problem 4548 美素数【打表】
    杭电 Problem 2008 分拆素数和 【打表】
    杭电 Problem 1722 Cake 【gcd】
    杭电 Problem 2187 悼念512汶川大地震遇难同胞——老人是真饿了【贪心】
    杭电Problem 1872 稳定排序
    杭电 Problem 1753 大明A+B
    东北林业大 564 汉诺塔
  • 原文地址:https://www.cnblogs.com/czyarl/p/14482409.html
Copyright © 2011-2022 走看看