Jzoj P3400 旅行___全排列+spfa

题目大意:

从前有一位旅者,他想要游遍天下所有的景点。这一天他来到了一个神奇的王国:在这片土地上,有n个城市,从1到n进行编号。王国中有m条道路,第i条道路连接着两个城市ai,bi,由于年代久远,所有的道路都已经不能使用。如果要修复第i条道路,需要wi的时间。为了更好的旅行,旅者想要将某些道路修复,使得1号城市能够到达n号城市,2号城市能够到达n-1号城市…k号城市能够到达n-k+1号城市。为了满足他的要求,请问最少需要多少时间去修复道路。无解请输出-1。
k<=4, n<=10000, m<=10000, n >= 2*k, wi<= 1000, 1 <= ai, bi <= n

分析:

全排列将修建1到k城市的顺序全部弄出来,
对于每个排列,
我们依次走,每次走完以后将其最短路上的值赋为0

代码:

#include 
#include 
#include 
#include 
#include 
#include 

#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)
#define mt(x) memset(x, 0, sizeof(x))
#define mp(x, y) memcpy(x, y, sizeof(y))
#define lson(x) x * 2 
#define rson(x) x * 2 + 1

#define inf 0x7fffffff
#define N 10005

using namespace std;
 
typedef long long ll;

struct Node {
	int To, nxt, w;
}e[N*2];
int num[24][4], orz[4], ood[N], rrd[N], dis[N], ls[N], w[N*2], n, m, K, tot, cnt = 1, sum, ans = inf;
bool vis[N], bz[4];

queue  Q;

void Addedge(int u, int v, int w) {
    e[++cnt].To = v, e[cnt].w = w, e[cnt].nxt = ls[u], ls[u] = cnt;
	e[++cnt].To = u, e[cnt].w = w, e[cnt].nxt = ls[v], ls[v] = cnt;
}

void dfs(int now) {
    if (now == K) {
        rep(i, 0, K - 1) num[tot][i] = orz[i]; tot++;
        return;
    }
    rep(i, 1, K)
        if (!bz[i]) {
            bz[i] = 1, orz[now] = i;
            dfs(now + 1);
            bz[i] = 0, orz[now] = 0;
        }
}

void spfa(int x) {
	while (Q.size()) Q.pop();
    rep(i, 1, n) dis[i] = inf, ood[i] = 0, rrd[i] = 0; 
	dis[x] = 0; vis[x] = 1;
	Q.push(x);
	while (Q.size()) {
		int u = Q.front(); Q.pop();
		for (int i = ls[u]; i; i = e[i].nxt) 
		    if (dis[e[i].To] > dis[u] + e[i].w) {
		    	dis[e[i].To] = dis[u] + e[i].w;
		    	ood[e[i].To] = i;
		    	rrd[e[i].To] = u;
				if (!vis[e[i].To]) 
				    vis[e[i].To] = 1, Q.push(e[i].To);
			}
		vis[u] = 0;
	}
	if (dis[n - x + 1] == inf) {
		printf("-1\n"); exit(0); 
	}
	sum += dis[n - x + 1];
    int eed = n - x + 1;
    for (; eed != x; eed = rrd[eed]) {
    	e[ood[eed]].w = 0;
    	e[ood[eed]^1].w = 0;
	}
}

int main() {
    scanf("%d %d %d", &n, &m, &K);
    int x, y, z;
    rep(i, 1, m) {
        scanf("%d %d %d", &x, &y, &z);
        Addedge(x, y, z);
    }
    rep(i, 1, cnt) w[i] = e[i].w;
    dfs(0);
	rep(i, 0, tot - 1) {
		rep(j, 1, cnt) e[j].w = w[j];
    	sum = 0;
        rep(j, 0, K - 1) spfa(num[i][j]); 
		ans = min(ans, sum);
	}
	printf("%d\n", ans);
    return 0;
}

你可能感兴趣的:(C++,排列组合,spfa)