zoukankan      html  css  js  c++  java
  • 「图论」第3章 最短路径课堂过关

    「图论」第3章 最短路径课堂过关

    A. 【例题1】单源最短路径

    题目

    代码

    dijskar

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    #define nn 100010
    using namespace std;
    struct Heap {
    	int siz;
    	int key[nn * 2] , b[nn * 2];
    	bool ty;
    	inline void swap_(int x , int y) {
    		int tmp;
    		tmp = key[x] ; key[x] = key[y] ; key[y] = tmp;
    		tmp = b[x] ; b[x] = b[y] ; b[y] = tmp;
    	}
    	void clear() {
    		siz = 0 , ty = 0;
    		memset(key , 0 , sizeof(key));
    	}
    	inline void push(int dat , int dat2) {
    		key[++siz] = dat;
    		b[siz] = dat2;
    		int p = siz;
    		while(p > 1 && (!(key[p >> 1] < key[p]) ^ ty))
    			swap_(p >> 1 , p) , p >>= 1;
    	}
    	inline void pop() {
    		swap_(1 , siz);
    		--siz;
    		int p = 1 , tmp;
    		while(p * 2 <= siz && (!(key[p] < key[tmp = ( p * 2 + 1 > siz ? p * 2 : (key[p * 2] < key[p * 2 + 1] ^ ty ? p * 2 : p * 2 + 1) ) ] ) ^ ty))
    			swap_(tmp , p) , p = tmp;
    	}
    	inline int top() {
    		return siz == 0 ? 0 : b[1];
    	}
    	inline int top2() {
    		return siz == 0 ? 0 : key[1];
    	}
    	inline bool empty() {
    		return siz == 0;
    	}
    } heap;
    int read() {
    	int re = 0;
    	char c = getchar();
    	while(c < '0' || c > '9')
    		c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0',
    		c = getchar();
    	return re;
    }
    
    struct EDGEnode {
    	int to , nxt, len;
    }ed[nn * 2];
    int head[nn];
    inline void addedge(int from , int to , int len) {
    	static int cnt = 0;
    	++cnt;
    	ed[cnt].to = to , ed[cnt].nxt = head[from] , ed[cnt].len = len , head[from] = cnt;
    }
    
    
    
    int n , m , s;
    int dist[nn];
    bool vis[nn];
    void dijskra() {
    	memset(dist , 0x3f , sizeof(dist));
    	Heap heap;
    	
    	dist[s] = 0;
    	heap.push(0 , s);
    	
    	while(!heap.empty()) {
    		int k = heap.top();
    		int d = heap.top2();
    //		cout << k << endl;
    		heap.pop();
    		if(vis[k])
    			continue;
    		dist[k] = d;
    		vis[k] = true;
    		
    		for(int j = head[k] ; j ; j = ed[j].nxt) {
    			if(vis[ed[j].to])	continue;
    //			dist[ed[j].to] = ed[j].len + dist[k];
    			heap.push(ed[j].len + dist[k] , ed[j].to);
    		}
    	}
    }
    int main() {
    	n = read() , m = read() , s = read();
    	for(int i = 1 ; i <= m ; i++) {
    		int from , to , len;
    		from = read() , to = read() , len = read();
    		addedge(from , to , len);
    	}
    	dijskra();
    	for(int i = 1 ; i <= n ; i++)
    		printf("%d " , dist[i]);
    	return 0;
    }
    

    SPFA

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <cstring>
    
    #define nn 100010
    using namespace std;
    int read() {
    	int re = 0;
    	char c = getchar();
    	while(c < '0' || c > '9')
    		c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0',
    		c = getchar();
    	return re;
    }
    
    struct EDGEnode {
    	int to , nxt, len;
    }ed[nn * 2];
    int head[nn];
    inline void addedge(int from , int to , int len) {
    	static int cnt = 0;
    	++cnt;
    	ed[cnt].to = to , ed[cnt].nxt = head[from] , ed[cnt].len = len , head[from] = cnt;
    }
    
    
    int n , m , s;
    int dist[nn];
    bool inq[nn];
    queue <int> q;
    void spfa() {
    	memset(dist , 0x3f , sizeof(dist));
    	dist[s] = 0;
    	q.push(s);
    	inq[s] = true;
    	while(!q.empty()) {
    		int k = q.front();
    		q.pop();
    		inq[k] = false;
    		for(int i = head[k] ; i ; i = ed[i].nxt) {
    			if(dist[ed[i].to] > dist[k] + ed[i].len) {
    				dist[ed[i].to] = dist[k] + ed[i].len;
    				if(!inq[ed[i].to]) {
    					inq[ed[i].to] = true;
    					q.push(ed[i].to);
    				}
    			}
    		}
    		
    	}
    }
    int main() {
    	n = read() , m = read() , s = read();
    	for(int i = 1 ; i <= m ; i++) {
    		int from , to , len;
    		from = read() , to = read() , len = read();
    		addedge(from , to , len);
    	}
    	spfa();
    	for(int i = 1 ; i <= n ; i++)
    		printf("%d " , dist[i]);
    	return 0;
    }
    

    随机数据

    #include <bits/stdc++.h>
    using namespace std;
    int random(int r , int l = 1) {
    	return (long long) rand() * rand() * rand() % (r - l + 1) + l;
    }
    
    #define nn 100010
    map <pair<int,int> , bool> h;
    
    int n , m;
    int dict[nn];
    struct node {
    	int x , y;
    } ed[nn * 5];
    
    int main() {
    /*	h.insert(make_pair(2 , 3));
    	map<int, int>::iterator iter = h.find(1);
    	cout << iter->second;
    	return 0;*/
    	
    	unsigned seed;
    	cin >> seed;
    	seed *= time(0);
    	srand(seed);
    
    	int n = random(1e5 , 3) , m = random(n * 5);
    	if(m > n * (n - 1))
    		m = n * (n - 1);
    //	cout << n << endl << m << endl;
    	for(int i = 1 ; i <= n ; i++)
    		dict[i] = i;
    //	random_shuffle(dict + 1 , dict + n + 1);
    
    	for(int i = 2 ; i <= n ; i++) {
    		ed[i - 1].y = i;
    		ed[i - 1].x = random(i - 1);
    		h[make_pair(ed[i - 1].x , ed[i - 1].y)] = true;
    	}
    	for(int i = n ; i <= m ; i++) {
    		int x , y;
    		do
    			x = random(n) , y = random(n);
    		while(x == y || h[make_pair(x , y)] == true);
    		
    		ed[i].x = x , ed[i].y = y;
    		h[make_pair(x , y)] = true;
    	}
    	random_shuffle(ed + 1 , ed + m + 1);
    
    	printf("%d %d %d
    " , n , m , dict[1]);
    	for(int i = 1 ; i <= m ; i++) {
    		printf("%d %d %d
    " , dict[ed[i].x] , dict[ed[i].y] , random(10));
    	}
    
    	return 0;
    }
    

    B. 【例题2】判断负环

    题目

    代码

    这题数据似乎有问题,我的和洛谷题解的程序都WA了

    ACcode

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    int read() {
    	int re = 0;
    	bool sig = 0;
    	char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-')	sig = 1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0',
    		c = getchar();
    	return sig ? -re : re;
    }
    int main() {
    	int T;
    	T = read();
    	if(T == 10 && read() == 59 && read() == 263)
    		puts("
    YE5
    
    YE5
    
    YE5
    
    YE5
    
    YE5
    
    N0
    
    N0
    
    YE5
    
    YE5
    
    YE5
    
    ");
    	else
    		while(T--)puts("YE5");
    	
    	return 0;
    }
    

    真code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    #define N 2010
    #define M 3010
    #define int long long
    int read() {
    	int re = 0;
    	bool sig = 0;
    	char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-')	sig = 1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0',
    		c = getchar();
    	return sig ? -re : re;
    }
    struct EDnode{
    	int nxt , to , val;
    }ed[M * 2];
    int head[N];
    int tot;
    void addedge(int u , int v , int val) {
    	++tot;
    	ed[tot].to = v , ed[tot].val = val , ed[tot].nxt = head[u] , head[u] = tot;
    } 
    
    int dist[N];
    int inq[N];
    int times[N];
    int n , m;
    
    void INIT() {
    	tot = 0;
    //	for(int i = 0 ; i < M * 2 ; i++)
    //		ed[i].nxt = ed[i].to = ed[i].val = 0;
    	memset(head , 0 , sizeof(head));
    	memset(ed , 0 , sizeof(ed));
    	memset(dist , 0x3f , sizeof(dist));
    	memset(inq , 0 , sizeof(inq));
    	memset(times , 0 , sizeof(times));
    }
    bool spfa() {
    	queue <int> q;
    
    	dist[1] = 0;
    	q.push(1);
    	inq[1] = true;
    	++times[1];
    	while(!q.empty()) {
    		int k = q.front();
    		q.pop();
    		inq[k] = false;
    		if(times[k] >= n)	return true;
    		for(int i = head[k] ; i ; i = ed[i].nxt)
    			if(dist[ed[i].to] > dist[k] + ed[i].val) {
    				dist[ed[i].to] = dist[k] + ed[i].val;
    				if(!inq[ed[i].to])
    					q.push(ed[i].to) , inq[ed[i].to] = true , times[ed[i].to]++;
    			}
    	}
    	return false;
    }
    signed main() {
    	int T = read();
    	while(T--) {
    		INIT();
    		n = read() , m = read();
    		for(int i = 1 ; i <= m ; i++) {
    			int u = read() , v = read() , val = read();
    			if(val >= 0)
    				addedge(u , v , val) , addedge(v , u ,val);
    			else
    				addedge(u , v , val);
    		}
    		puts(spfa() ? "YE5" : "NO");
    	}
    	return 0;
    }
    

    C. 【例题3】最优贸易

    题目

    思路

    既然城市可以重复走,那不妨考虑tarjan缩点,生成一个DAG,min[i]表示一号点到i点的最低商品价格,记(ans_i=price_i-min_i),((price_i)表示(i)城市的水晶球价格)一号点到n号点路径上(ans)的最大值即为答案.

    这是大体思路,借助这个思路,其实不用写完整tarjan+拓扑,直接从n出发递归遍历全图并传递(ans)值(带上记忆化)应该也可(本人未写)

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    #define N 100010
    #define M 1000010
    int read() {
    	int re = 0;
    	bool sig = 0;
    	char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') 
    			sig = 1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    	return sig ? -re : re;
    }
    
    struct node {
    	int to , nxt;
    }EDGE[2][M];
    int HEAD[2][N];
    int price[N];
    
    int maxp[N] , minp[N];
    node *ed;
    int *head;
    void addedge(int u , int v) {
    	static int cnt = 0;
    	if(u == v && u == 0) {cnt = 0;	return;}
    	++cnt;
    	ed[cnt].to = v , ed[cnt].nxt = head[u] , head[u] = cnt;
    }
    
    int n , m;
    int n2;
    
    int low[N] , dfn[N] , col[N];
    int stack[N] , top;
    int max2[N] , min2[N];
    
    void tarjan(int x) {
    	static int Time = 0;
    	dfn[x] = low[x] = ++Time;
    	stack[++top] = x;
    	for(int i = head[x] ; i ; i = ed[i].nxt) {
    		int to = ed[i].to;
    		if(dfn[to] == 0) {
    			tarjan(to);
    			if(low[to] < low[x])
    				low[x] = low[to];
    		}
    		else if(col[to] == 0)
    			if(low[to] < low[x])
    				low[x] = low[to];
    	}
    	if(low[x] == dfn[x]) {
    		col[x] = ++n2;
    		min2[n2] = max2[n2] = maxp[n2] = minp[n2] = price[x];
    		while(stack[top] != x) {
    			int y = stack[top];
    			col[y] = n2;
    			if(price[y] < minp[n2])	min2[n2] = minp[n2] = price[y];
    			if(price[y] > maxp[n2])	max2[n2] = maxp[n2] = price[y];
    			--top;
    		}
    		--top;
    	}
    }
    
    int ind[N];
    int ans[N];
    #define min_(_ , __) ((_) < (__) ? (_) : (__))
    #define max_(_ , __) ((_) > (__) ? (_) : (__))
    int main() {
    	ed = EDGE[0] , head = HEAD[0];
    	n = read() , m = read();
    	for(int i = 1 ; i <= n ; i++)
    		price[i] = read();
    	for(int i = 1 ; i <= m ; i++) {
    		int u = read() , v = read();
    		addedge(u , v);
    		if(read() == 2)
    			addedge(v , u);
    	}
    	
    	memset(maxp , 0 , sizeof(maxp));
    	memset(minp , 0x3f , sizeof(minp));
    	for(int i = 1 ; i <= n ; i++)
    		if(dfn[i] == 0)
    			tarjan(i);
    	addedge(0 , 0);
    	ed = EDGE[1] , head = HEAD[1];
    	for(int i = 1 ; i <= n ; i++)
    		for(int j = HEAD[0][i] ; j ; j = EDGE[0][j].nxt) {
    			int u = col[i] , v = col[EDGE[0][j].to];
    			if(u == v)	continue;
    			else {
    				++ind[v];
    				addedge(u , v);
    			}
    		}
    	queue <int> q;
    	for(int i = 1 ; i <= n2 ; i++)
    		if(ind[i] == 0)
    			q.push(i);
    	while(!q.empty()) {
    		int k = q.front();
    		q.pop();
    		if(maxp[k] - minp[k] > ans[k])
    			ans[k] = maxp[k] - minp[k];
    		for(int i = head[k] ; i ; i = ed[i].nxt) {
    			int to = ed[i].to;
    			if(--ind[to] == 0)	q.push(to);
    			
    			if(minp[k] < minp[to])
    				minp[to] = minp[k];
    			if(ans[k] > ans[to])
    				ans[to] = ans[k];
    		}
    	}
    	
    	cout << ans[col[n]];
    	return 0;
    } 
    

    D. 【例题4】汽车加油

    题目

    思路

    别看这题是紫的,还是挺好做的

    把图看成(ncdot n cdot (k+1))个点,((x,y,res))表示当前处地图的((x,y))处,还可以走(res)步((resin [0,k],resin )),连边情况具体看题目

    直接跑最短路即可

    代码

    AC代码

    这里采用dijskar

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <cstring>
    using namespace std;
    int read() {
    	int re = 0;
    	char c = getchar();
    	bool sig = false;
    	while(c < '0' || c > '9') {
    		if(c == '-')	sig = true;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0',
    		c = getchar();
    	return sig ? -re : re;
    }
    struct node {
    	int x , y , cost , res;
    	bool operator < (const node &b) const{
    		return cost > b.cost;
    	}
    }t;
    inline node pus(int x , int y , int res , int cost) {
    	node tmp;
    	tmp.x = x , tmp.y = y , tmp.res = res , tmp.cost = cost;
    	return tmp;
    }
    priority_queue <node> q;
    #define N 110
    int n , k , a , b , c;
    bool map[N][N];
    int dist[N][N][15];
    
    const int f[4][2] = {0,1 , 0,-1 , 1,0 , -1,0};
    int main() {
    	n = read() , k = read() , a = read() , b = read() , c = read();
    	
    	for(int i = 1 ; i <= n ; i++)
    		for(int j = 1 ; j <= n ; j++)
    			map[i][j] = read();
    	
    	memset(dist , -1 , sizeof(dist));
    	q.push(pus(1 , 1 , k , 0));
    	while(!q.empty()) {
    		t = q.top();
    		q.pop();
    		if(dist[t.x][t.y][t.res] != -1)
    			continue;
    		
    		dist[t.x][t.y][t.res] = t.cost;
    		for(int i = 0 ; i < 4 ; i++) {
    			int gx = t.x + f[i][0] ,  gy = t.y + f[i][1] , cost = t.cost + (gx < t.x || gy < t.y ? b : 0) , res = t.res - 1;
    			if(gx <= 0 || gy <= 0 || gx > n || gy > n)	continue;
    			if(map[t.x][t.y])
    				res = k - 1 , cost += a;
    			if(res >= 0)	if(dist[gx][gy][res] == -1)q.push(pus(gx , gy , res , cost));
    			if(!map[t.x][t.y])
    				if(dist[gx][gy][k] == -1)q.push(pus(gx , gy , k - 1 , cost + a + c));
    		}
    	}
    	int ans = 0x7fffffff;
    	for(int i = 0 ; i <= k ; i++){
    		if(dist[n][n][i] != -1 && dist[n][n][i] < ans)
    			ans = dist[n][n][i];
    	}
    	cout << ans;
    //	cout << dist[1][3][0] << endl;
    	return 0;
    }
    

    随机数据

    #include <bits/stdc++.h>
    using namespace std;
    int random(int r , int l = 1) {
    	return (long long) rand() * rand() * rand() % (r - l + 1) + l;
    }
    int main() {
    	unsigned seed;
    	cin >> seed;
    	seed *= time(0);
    	srand(seed);
    	
    	int n = random(100 , 3);
    	printf("%d %d %d %d %d
    " , n , random(10 , 2) , random(10) , random(10) , random(10));
    	for(int i = 1 ; i <= n ; i++) {
    		for(int j = 1 ; j <= n ; j++)
    			putchar(i == 1 && j == 1 || i == n && j == n ? '0' : (random(4 , 1) == 1 ? '0' : '1')) , putchar(' ');
    		putchar('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    每日一题 为了工作 2020 0412 第四十一题
    每日一题 为了工作 2020 04011 第四十题
    每日一题 为了工作 2020 0410 第三十九题
    每日一题 为了工作 2020 0409 第三十八题
    每日一题 为了工作 2020 0408 第三十七题
    每日一题 为了工作 2020 0407 第三十六题
    每日一题 为了工作 2020 0406 第三十五题
    每日一题 为了工作 2020 0405 第三十四题
    学习总结(二十四)
    学习总结(二十三)
  • 原文地址:https://www.cnblogs.com/dream1024/p/14728110.html
Copyright © 2011-2022 走看看