ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 最短路

2021-08-12 19:33:19  阅读:154  来源: 互联网

标签:fir int 题解 短路 sec ans rec dis


传送门

是 @Yubai 的思路

发现一个点还可以被倒着经过一次就很烦
可以另外建出一类全是反向的边,这样就变成了从同一起点出发,到达同一终点的最短路
然而这两个几乎不是一个图,考虑二维spfa
令 \(dis[i][j]\) 为正向走到 \(i\) ,逆向走到 \(j\) 的最短长度
再令 \(rec[i][j]\) 为正向走到 \(i\) ,逆向走到 \(j\) 的最短路经过的点集
二维spfa跑一遍就行了
至于有两个状态同时转移到了一个点且dis相同的情况该保留谁的rec
随便选一个就行,它确实不会产生影响
考虑我们构造一组数据来卡它的过程
我们会试着构造一种情况使它在从n往回走的时候经过仅有其中一个点集里有的点
然而我们DP定义是什么?正向走到 \(i\) ,逆向走到 \(j\)
我们已经把逆向走转化为正向走了,也就消除了后效性
所以没有影响

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 255
#define ll long long 
#define reg register int 
#define fir first
#define sec second
#define make make_pair
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int head[N], rhead[N], size, val[N], dis[N];
bool vis[N], could[N];
struct edge{int to, next;}e[N*N*2];
inline void add1(int s, int t) {e[++size].to=t; e[size].next=head[s]; head[s]=size;}
inline void add2(int s, int t) {e[++size].to=t; e[size].next=rhead[s]; rhead[s]=size;}
void spfa(int s) {
	memset(dis, 127, sizeof(int)*(n+1));
	dis[s]=0;
	queue<int> q;
	q.push(s);
	int u;
	while (q.size()) {
		u=q.front(); q.pop();
		vis[u]=0;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (!could[v]) continue;
			if (dis[v]>dis[u]) {
				dis[v]=dis[u];
				if (!vis[v]) q.push(v), vis[v]=1;
			}
		}
	}
}

namespace force{
	void solve() {
		int lim=1<<n, sum, ans=INF;
		for (reg s=1; s<lim; ++s) {
			if (!(s&1) || !(s&(1<<(n-1)))) continue;
			sum=0;
			memset(could, 0, sizeof(could));
			for (reg i=0; i<n; ++i) if (s&(1<<i)) sum+=val[i+1], could[i+1]=1;
			if (sum>=ans) goto jump;
			spfa(1); if (dis[n]) goto jump;
			spfa(n); if (dis[1]) goto jump;
			ans = min(ans, sum);
			jump: ;
		}
		printf("%d\n", ans==INF?-1:ans);
		exit(0);
	}
}

namespace task1{
	void solve() {
		srand(time(0));
		int sum, ans=INF;
		int buc[N];
		for (int i=1; i<=n; ++i) buc[i]=i;
		for (int T=1,num; ; ++T) {
			if ((!(T%10))&&clock()>850000) break;
			memset(could, 0, sizeof(bool)*(n+1));
			random_shuffle(buc+1, buc+n+1);
			num=rand()%n+1;
			could[1]=could[n]=1;
			sum=val[1]+val[n];
			for (reg i=1; i<=num; ++i)
				if (buc[i]!=1 && buc[i]!=n) 
					sum+=val[buc[i]], could[buc[i]]=1;
			if (sum>=ans) goto jump2;
			spfa(1); if (dis[n]) goto jump2;
			spfa(n); if (dis[1]) goto jump2;
			ans = min(ans, sum);
			jump2: ;
		}
		printf("%d\n", ans==INF?-1:ans);
		exit(0);
	}
}

namespace task{
	int dis[N][N];
	bool vis[N][N];
	bitset<256> rec[N][N];
	void spfa(int s) {
		memset(dis, 127, sizeof(dis));
		dis[s][s]=val[s]; rec[s][s][s]=1;
		queue< pair<int, int> > q;
		q.push(make(s, s));
		pair<int, int> u;
		while (q.size()) {
			u=q.front(); q.pop();
			//cout<<"u: "<<u.fir<<' '<<u.sec<<endl;
			vis[u.fir][u.sec]=0;
			for (int i=head[u.fir],v,sum; ~i; i=e[i].next) {
				v = e[i].to;
				//cout<<"v: "<<v<<endl;
				sum=dis[u.fir][u.sec]+(rec[u.fir][u.sec][v]?0:val[v]);
				if (dis[v][u.sec] > sum) {
					dis[v][u.sec]=sum; rec[v][u.sec]=rec[u.fir][u.sec];
					rec[v][u.sec][v]=1;
					if (!vis[v][u.sec]) q.push(make(v, u.sec)), vis[v][u.sec]=1;
				}
			}
			
			for (int i=rhead[u.sec],v,sum; ~i; i=e[i].next) {
				v = e[i].to;
				//cout<<"v: "<<v<<endl;
				sum=dis[u.fir][u.sec]+(rec[u.fir][u.sec][v]?0:val[v]);
				if (dis[u.fir][v] > sum) {
					dis[u.fir][v]=sum; rec[u.fir][v]=rec[u.fir][u.sec];
					rec[u.fir][v][v]=1;
					if (!vis[u.fir][v]) q.push(make(u.fir, v)), vis[u.fir][v]=1;
				}
			}
		}
	}
	void solve() {
		spfa(1);
		printf("%d\n", dis[n][n]==2139062143?-1:dis[n][n]);
		exit(0);
	}
}

signed main()
{
	memset(head, -1, sizeof(head));
	memset(rhead, -1, sizeof(rhead)); 
	
	n=read(); m=read();
	if (!m) {puts("-1"); return 0;}
	for (int i=1; i<=n; ++i) val[i]=read();
	for (int i=1,u,v; i<=m; ++i) {u=read(); v=read(); add1(u, v); add2(v, u);}
	//if (n<=20) force::solve();
	//else task1::solve();
	task::solve();
	
	return 0;
}

标签:fir,int,题解,短路,sec,ans,rec,dis
来源: https://www.cnblogs.com/narration/p/15134329.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有