题解 最短路

传送门

是 @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;
}
上一篇:【洛谷】P1107 [BJWC2008]雷涛的小猫


下一篇:MySQL Innodb Engine--修改数据时先写Buffer Pool还是先写Redo Log